chromium/ios/chrome/browser/shared/model/web_state_list/tab_group_range.h

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef IOS_CHROME_BROWSER_SHARED_MODEL_WEB_STATE_LIST_TAB_GROUP_RANGE_H_
#define IOS_CHROME_BROWSER_SHARED_MODEL_WEB_STATE_LIST_TAB_GROUP_RANGE_H_

#import <set>

#import "base/check_op.h"

// Represents the range of a TabGroup in its owning WebStateList.
class TabGroupRange {
 public:
  // Initializes the range with a start and count.
  constexpr TabGroupRange(int start, int count) : start_(start), count_(count) {
    DCHECK_GE(count_, 0);
  }

  // Returns a range that is invalid, which is {-1, 0}.
  static constexpr TabGroupRange InvalidRange() { return TabGroupRange(-1, 0); }

  // Checks if the range is valid, i.e. is not empty.
  constexpr bool valid() const { return count_ > 0; }

  // Getters.
  constexpr int range_begin() const { return start_; }
  constexpr int count() const { return count_; }
  std::set<int> AsSet() const { return std::set<int>(begin(), end()); }

  // `range_end` is the first index not in the range.
  constexpr int range_end() const { return start_ + count_; }
  // Whether the index is inside the range.
  constexpr bool contains(int index) const {
    return start_ <= index && index < start_ + count_;
  }

  // Updates the range by moving it. The count stays the same, but
  // `range_begin` increases by `delta`. If `delta` is positive, the group
  // moves to the right. Otherwise, it moves to the left.
  constexpr void Move(int delta) {
    if (delta < 0) {
      MoveLeft(-delta);
    } else {
      MoveRight(delta);
    }
  }

  // Updates the range by moving it in a given direction. By default, it moves
  // by one.
  constexpr void MoveLeft(int delta = 1) {
    CHECK_GE(delta, 0);
    CHECK_GE(start_, delta);
    start_ -= delta;
  }
  constexpr void MoveRight(int delta = 1) {
    CHECK_GE(delta, 0);
    CHECK_LT(start_, INT_MAX - delta);
    start_ += delta;
  }

  // Updates the range by expanding/contracting by one in a given direction.
  constexpr void ExpandLeft() {
    MoveLeft();
    ExpandRight();
  }
  constexpr void ExpandRight() { ++count_; }
  constexpr void ContractLeft() {
    MoveRight();
    ContractRight();
  }
  constexpr void ContractRight() {
    CHECK_GT(count_, 0);
    --count_;
  }

  constexpr bool operator==(const TabGroupRange& other) const = default;
  constexpr bool operator!=(const TabGroupRange& other) const = default;

  // Support for range-based for-loops. Ex:
  //
  //  TabGroupRange range = ...;
  //  for (int i : range) {
  //    // ... do something with the index from the range.
  //  }
  //
  class iterator {
   public:
    constexpr iterator(int current) : current_(current) {}

    int operator*() const { return current_; }
    void operator++() { ++current_; }
    bool operator!=(const iterator& other) const {
      return current_ != other.current_;
    }

   private:
    int current_;
  };
  iterator begin() const { return iterator{start_}; }
  iterator end() const { return iterator{range_end()}; }

 private:
  int start_;
  int count_;
};

#endif  // IOS_CHROME_BROWSER_SHARED_MODEL_WEB_STATE_LIST_TAB_GROUP_RANGE_H_