diff --git a/huffman/BUILD.bazel b/huffman/BUILD.bazel index 287a27d..f7cc9a7 100644 --- a/huffman/BUILD.bazel +++ b/huffman/BUILD.bazel @@ -6,6 +6,7 @@ cc_library( "src/bit.hpp", "src/code.hpp", "src/detail/base_view.hpp", + "src/detail/iterator_interface.hpp", "src/detail/static_vector.hpp", "src/detail/table_node.hpp", "src/detail/table_storage.hpp", diff --git a/huffman/src/detail/base_view.hpp b/huffman/src/detail/base_view.hpp index 1e217bf..7e84445 100644 --- a/huffman/src/detail/base_view.hpp +++ b/huffman/src/detail/base_view.hpp @@ -1,5 +1,7 @@ #pragma once +#include "huffman/src/detail/iterator_interface.hpp" + #include #include #include @@ -11,7 +13,7 @@ namespace gpu_deflate::huffman::detail { /// @tparam V underlying view /// @tparam B base class /// -template +template requires std::ranges::view and std::same_as, std::ranges::sentinel_t> and @@ -20,7 +22,7 @@ class base_view : public std::ranges::view_interface> { // This is largely adapted from `transform_view` (or other views), although we // apply some simplifications: - // * V must model `forward_range` instead of `input_range` + // * V must model `random_access_range` instead of `input_range` // * sentinel_t is the same as iterator_t // // https://eel.is/c++draft/range.transform @@ -28,7 +30,7 @@ class base_view : public std::ranges::view_interface> V base_{}; public: - class iterator + class iterator : public iterator_interface { using base_iterator = std::ranges::iterator_t; base_iterator base_{}; @@ -56,78 +58,21 @@ class base_view : public std::ranges::view_interface> { return static_cast(*base_); } - constexpr auto operator->() const -> pointer { return &**this; } - - constexpr auto operator++() -> iterator& - { - ++base_; - return *this; - } - constexpr auto operator++(int) -> iterator - { - auto tmp = *this; - ++*this; - return tmp; - } - - constexpr auto operator--() -> iterator& - requires std::ranges::bidirectional_range - { - --base_; - return *this; - } - constexpr auto operator--(int) -> iterator - requires std::ranges::bidirectional_range - { - auto tmp = *this; - --*this; - return tmp; - } constexpr auto operator+=(difference_type n) -> iterator& - requires std::ranges::random_access_range { base_ += n; return *this; } - constexpr auto operator-=(difference_type n) -> iterator& - requires std::ranges::random_access_range - { - base_ -= n; - return *this; - } - constexpr auto operator[](difference_type n) const -> reference - requires std::ranges::random_access_range - { - return static_cast(base_[n]); - } - - friend constexpr auto - operator<=>(const iterator&, const iterator&) = default; - - friend constexpr auto operator+(iterator i, difference_type n) -> iterator - requires std::ranges::random_access_range - { - return i += n; - } - friend constexpr auto operator+(difference_type n, iterator i) -> iterator - requires std::ranges::random_access_range - { - return i + n; - } - - friend constexpr auto operator-(iterator i, difference_type n) -> iterator - requires std::ranges::random_access_range - { - return i -= n; - } friend constexpr auto operator-(const iterator& x, const iterator& y) -> difference_type - requires std::ranges::random_access_range { return x.base() - y.base(); } + + friend constexpr auto + operator<=>(const iterator&, const iterator&) = default; }; base_view() diff --git a/huffman/src/detail/iterator_interface.hpp b/huffman/src/detail/iterator_interface.hpp new file mode 100644 index 0000000..c0a718a --- /dev/null +++ b/huffman/src/detail/iterator_interface.hpp @@ -0,0 +1,107 @@ +#pragma once + +#include +#include + +namespace gpu_deflate::huffman::detail { + +/// CRTP helper class used to synthesize operations for a random access iterator +/// @tparam D derived iterator type +/// +/// A simplified implementation of `iterator_interface`. This CRTP helper class +/// synthesizes iterator operations given a basis set of operations. This type +/// currently requires `D` to implement the following operations: +/// * operator*() const -> reference +/// * operator+=(difference_type) -> D& +/// and the following static member typedefs +/// * pointer +/// * reference +/// * difference_type +/// +/// Note that `D` must also define the following operations to model +/// `std::random_access_iterator` +/// * D() +/// * operator-(const D&, const D&) -> difference_type +/// * operator<=>(const D&, const D&) +/// and static member typedefs +/// * iterator_category +/// * value_type +/// +template +struct iterator_interface +{ + + template + constexpr auto operator->() const -> typename I::pointer + { + return &*static_cast(*this); + } + + template + constexpr auto operator++() -> I& + { + return static_cast(*this) += typename I::difference_type{1}; + } + + template + constexpr auto operator++(int) -> I + { + auto tmp = *this; + ++*this; + return tmp; + } + + template + constexpr auto operator--() -> I& + { + return *this -= typename I::difference_type{1}; + } + + template + constexpr auto operator--(int) -> I + { + auto tmp = *this; + --*this; + return tmp; + } + + template + constexpr auto operator-=(typename I::difference_type n) -> I& + { + return static_cast(*this) += -n; + } + + template + constexpr auto + operator[](typename I::difference_type n) const -> typename I::reference + { + return *(*this + n); + } + + template I> + friend constexpr auto operator+(I i, typename I::difference_type n) -> I + { + return i += n; + } + + template I> + friend constexpr auto operator+(typename I::difference_type n, I i) -> I + { + return i + n; + } + + template I> + friend constexpr auto operator-(I i, typename I::difference_type n) -> I + { + return i + -n; + } + + /// Default three-way comparison + /// + // This must be defined to allow three-way comparison for derived class `I` to + // be defaulted. + friend constexpr auto + operator<=>(const iterator_interface&, const iterator_interface&) = default; +}; + +} // namespace gpu_deflate::huffman::detail