Program Listing for File indexing_iterator.hpp

Return to documentation for file (include/beluga/utility/indexing_iterator.hpp)

// Copyright 2024 Ekumen, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef BELUGA_UTILITY_INDEXING_ITERATOR_HPP
#define BELUGA_UTILITY_INDEXING_ITERATOR_HPP

#include <cstdint>
#include <iterator>
#include <type_traits>

namespace beluga {


template <class Indexable, class Index = typename Indexable::size_type>
class IndexingIterator {
 public:
  using value_type =
      std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Indexable>()[std::declval<Index>()])>>;
  using reference = decltype(std::declval<Indexable>()[std::declval<Index>()]);
  using pointer = decltype(std::addressof(std::declval<Indexable>()[std::declval<Index>()]));
  using difference_type = std::make_signed_t<decltype(std::declval<Index>() - std::declval<Index>())>;
  using iterator_category = std::random_access_iterator_tag;

  explicit IndexingIterator() = default;

  explicit IndexingIterator(Indexable* indexable, Index cursor = Index{})
      : indexable_{indexable}, cursor_{std::move(cursor)} {}

  explicit IndexingIterator(Indexable& indexable, Index cursor = Index{})
      : IndexingIterator(std::addressof(indexable), std::move(cursor)) {}

  IndexingIterator operator++(int) noexcept {
    IndexingIterator other = *this;
    ++(*this);
    return other;
  }

  IndexingIterator& operator++() noexcept {
    ++cursor_;
    return *this;
  }

  IndexingIterator operator--(int) noexcept {
    IndexingIterator other = *this;
    --(*this);
    return other;
  }

  IndexingIterator& operator--() noexcept {
    --cursor_;
    return *this;
  }

  IndexingIterator& operator+=(difference_type offset) noexcept {
    using raw_difference_type = decltype(cursor_ - cursor_);
    if (offset < 0) {
      cursor_ -= static_cast<raw_difference_type>(-offset);
    } else {
      cursor_ += static_cast<raw_difference_type>(offset);
    }
    return *this;
  }

  [[nodiscard]] IndexingIterator operator+(difference_type offset) const noexcept {
    IndexingIterator other = *this;
    other += offset;
    return other;
  }

  [[nodiscard]] friend IndexingIterator operator+(difference_type offset, const IndexingIterator& iterator) {
    return iterator + offset;
  }

  IndexingIterator& operator-=(difference_type offset) noexcept {
    using raw_difference_type = decltype(cursor_ - cursor_);
    if (offset < 0) {
      cursor_ += static_cast<raw_difference_type>(-offset);
    } else {
      cursor_ -= static_cast<raw_difference_type>(offset);
    }
    return *this;
  }

  [[nodiscard]] IndexingIterator operator-(difference_type offset) const noexcept {
    IndexingIterator other = *this;
    other -= offset;
    return other;
  }

  [[nodiscard]] difference_type operator-(const IndexingIterator& other) const noexcept {
    if (cursor_ < other.cursor_) {
      return -static_cast<difference_type>(other.cursor_ - cursor_);
    }
    return static_cast<difference_type>(cursor_ - other.cursor_);
  }


  [[nodiscard]] reference operator[](difference_type offset) const noexcept { return (*indexable_)[cursor_ + offset]; }


  [[nodiscard]] reference operator*() const noexcept { return (*indexable_)[cursor_]; }


  [[nodiscard]] pointer operator->() const noexcept { return std::addressof((*indexable_)[cursor_]); }


  bool operator<(const IndexingIterator& other) const noexcept {
    return indexable_ == other.indexable_ && cursor_ < other.cursor_;
  }


  bool operator<=(const IndexingIterator& other) const noexcept {
    return indexable_ == other.indexable_ && cursor_ <= other.cursor_;
  }


  bool operator>(const IndexingIterator& other) const noexcept { return !((*this) <= other); }


  bool operator>=(const IndexingIterator& other) const noexcept { return !((*this) < other); }


  bool operator==(const IndexingIterator& other) const noexcept {
    return indexable_ == other.indexable_ && cursor_ == other.cursor_;
  }

  bool operator!=(const IndexingIterator& other) const noexcept { return !(*this == other); }

 private:
  Indexable* indexable_{nullptr};
  Index cursor_{};
};

}  // namespace beluga

#endif