// SPDX-License-Identifier: BSD-2-Clause // author: Max Kellermann #pragma once #include #include /** * An iterator wrapper that dereferences the values returned by the * original iterator. */ template::value_type>())>> class DereferenceIterator { /* this friend declaration allows the template operator==() to compare arbitrary specializations */ template friend class DereferenceIterator; using Traits = std::iterator_traits; IT original; public: using iterator_category = typename Traits::iterator_category; using difference_type = typename Traits::difference_type; using value_type = VT; using pointer = VT *; using reference = VT &; constexpr DereferenceIterator() = default; constexpr DereferenceIterator(const IT _original) noexcept :original(_original) {} constexpr reference operator*() const noexcept { return static_cast(**original); } constexpr pointer operator->() const noexcept { return static_cast(&**original); } constexpr auto &operator++() noexcept { ++original; return *this; } constexpr auto operator++(int) noexcept { auto old = *this; ++original; return old; } constexpr auto &operator+=(difference_type n) noexcept { original += n; return *this; } constexpr auto operator+(difference_type n) const noexcept { return DereferenceIterator{original + n}; } constexpr auto &operator--() noexcept { --original; return *this; } constexpr auto operator--(int) noexcept { auto old = *this; --original; return old; } constexpr auto &operator-=(difference_type n) noexcept { original -= n; return *this; } constexpr auto operator-(difference_type n) const noexcept { return DereferenceIterator{original - n}; } /* this is a template to allow comparisons with sentinel end iterators */ template constexpr bool operator==(const DereferenceIterator &other) const noexcept { return original == other.original; } }; /** * A container wrapper that wraps the iterators in a * DereferenceIterator. */ template::value_type>> class DereferenceContainerAdapter { CT original; /* these aliases allow the underlying container to return a different type for begin() and end() */ using const_end_iterator = DereferenceIterator().cend()), const VT>; using end_iterator = DereferenceIterator().end()), VT>; public: using value_type = VT; using pointer = VT *; using reference = VT &; using const_iterator = DereferenceIterator().cbegin()), const VT>; using iterator = DereferenceIterator().begin()), VT>; explicit constexpr DereferenceContainerAdapter(CT &&_original) noexcept :original(std::move(_original)) {} constexpr iterator begin() noexcept { return original.begin(); } constexpr const_iterator begin() const noexcept { return original.cbegin(); } constexpr const_iterator cbegin() const noexcept { return original.cbegin(); } constexpr end_iterator end() noexcept { return original.end(); } constexpr const_end_iterator end() const noexcept { return original.cend(); } constexpr const_end_iterator cend() const noexcept { return original.cend(); } };