diff --git a/cpl/inc/tree.h b/cpl/inc/tree.h index 32b68c9..8a742fe 100644 --- a/cpl/inc/tree.h +++ b/cpl/inc/tree.h @@ -9,116 +9,226 @@ #include "xcore.h" +#include #include #include CPL_BEGIN -#ifdef USE_DISJOINT_SET_ITERATORS template -class _Disjoint_set_const_iterator { +class disjoint_set_const_iterator { public: using iterator_category = std::random_access_iterator_tag; + using iterator_concept = std::random_access_iterator_tag; + using difference_type = std::ptrdiff_t; + +private: + using parent_value_type = typename MyDisj::value_type; + using parent_rank_type = typename MyDisj::rank_type; + + using parent_iterator = typename std::vector::const_iterator; + using rank_iterator = typename std::vector::const_iterator; protected: - using parent_iterator = typename std::vector::iterator; - using rank_iterator = typename std::vector::iterator; + using pair_cref = std::pair; + + struct arrow_proxy { + pair_cref ref; + + const pair_cref* operator->() const noexcept { + return &ref; + } + }; public: - using value_type = std::pair; - using difference_type = std::ptrdiff_t; - using pointer = value_type*; - using const_pointer = value_type*; - using reference = value_type&; - using const_reference = const value_type&; + using value_type = std::pair; + using reference = value_type; + using const_reference = value_type; + using pointer = const value_type*; + using const_pointer = const value_type*; - _Disjoint_set_const_iterator(parent_iterator parent, rank_iterator rank) noexcept : parent(parent), rank(rank) {} + disjoint_set_const_iterator() = default; - [[nodiscard]] value_type operator*() const noexcept { - return {(*parent), (*rank)}; + disjoint_set_const_iterator(parent_iterator parent, rank_iterator rank) noexcept : parent(parent), rank(rank) {} + + [[nodiscard]] reference operator*() const noexcept { + return reference{*parent, *rank}; } - [[nodiscard]] pointer operator->() const noexcept { - return &operator*(); + [[nodiscard]] arrow_proxy operator->() const noexcept { + return arrow_proxy{reference{*parent, *rank}}; } - _Disjoint_set_const_iterator& operator++() noexcept { + disjoint_set_const_iterator& operator++() noexcept { ++parent; ++rank; return *this; } - _Disjoint_set_const_iterator& operator++(int) noexcept { + disjoint_set_const_iterator operator++(int) noexcept { auto tmp = *this; ++(*this); return tmp; } - _Disjoint_set_const_iterator& operator--() noexcept { + disjoint_set_const_iterator& operator--() noexcept { --parent; --rank; return *this; } - _Disjoint_set_const_iterator& operator--(int) noexcept { + disjoint_set_const_iterator operator--(int) noexcept { auto tmp = *this; --(*this); return tmp; } - [[nodiscard]] _Disjoint_set_const_iterator& operator+=(const difference_type off) noexcept { + [[nodiscard]] disjoint_set_const_iterator& operator+=(const difference_type off) noexcept { parent += off; rank += off; return *this; } - [[nodiscard]] _Disjoint_set_const_iterator operator+(const difference_type off) const noexcept { + [[nodiscard]] disjoint_set_const_iterator operator+(const difference_type off) const noexcept { auto tmp = *this; tmp += off; return tmp; } - [[nodiscard]] friend _Disjoint_set_const_iterator operator+( - const difference_type off, _Disjoint_set_const_iterator next) noexcept { + [[nodiscard]] friend disjoint_set_const_iterator operator+( + const difference_type off, disjoint_set_const_iterator next) noexcept { next += off; return next; } - [[nodiscard]] _Disjoint_set_const_iterator& operator-=(const difference_type off) noexcept { + [[nodiscard]] disjoint_set_const_iterator& operator-=(const difference_type off) noexcept { return *this += -off; } - [[nodiscard]] _Disjoint_set_const_iterator operator-(const difference_type off) const noexcept { + [[nodiscard]] disjoint_set_const_iterator operator-(const difference_type off) const noexcept { auto tmp = *this; tmp -= off; return tmp; } - [[nodiscard]] difference_type operator-(const _Disjoint_set_const_iterator& right) const noexcept { + [[nodiscard]] difference_type operator-(const disjoint_set_const_iterator& right) const noexcept { return static_cast(parent - right.parent); } - [[nodiscard]] bool operator==(const _Disjoint_set_const_iterator& right) const noexcept { + [[nodiscard]] reference operator[](const difference_type off) const noexcept { + return *(*this + off); + } + + [[nodiscard]] bool operator==(const disjoint_set_const_iterator& right) const noexcept { return parent == right.parent; } - [[nodiscard]] bool operator!=(const _Disjoint_set_const_iterator& right) const noexcept { + [[nodiscard]] bool operator!=(const disjoint_set_const_iterator& right) const noexcept { return !(*this == right); } + [[nodiscard]] bool operator<(const disjoint_set_const_iterator& right) const noexcept { + return parent < right.parent; + } + + [[nodiscard]] bool operator>(const disjoint_set_const_iterator& right) const noexcept { + return right < *this; + } + + [[nodiscard]] bool operator<=(const disjoint_set_const_iterator& right) const noexcept { + return !(right < *this); + } + + [[nodiscard]] bool operator>=(const disjoint_set_const_iterator& right) const noexcept { + return !(*this < right); + } + protected: parent_iterator parent; rank_iterator rank; }; template -class _Disjoint_set_iterator : public _Disjoint_set_const_iterator { +class disjoint_set_iterator : public disjoint_set_const_iterator { protected: - using _Mybase = _Disjoint_set_const_iterator; + using Mybase = disjoint_set_const_iterator; public: - using _Mybase::_Mybase; + using iterator_category = std::random_access_iterator_tag; + using iterator_concept = std::random_access_iterator_tag; + using difference_type = typename Mybase::difference_type; + + using value_type = typename Mybase::value_type; + using reference = typename Mybase::reference; + using pointer = typename Mybase::pointer; + + using Mybase::Mybase; + + [[nodiscard]] reference operator*() const noexcept { + return Mybase::operator*(); + } + + [[nodiscard]] Mybase::arrow_proxy operator->() const noexcept { + return Mybase::operator->(); + } + + disjoint_set_iterator& operator++() noexcept { + Mybase::operator++(); + return *this; + } + + disjoint_set_iterator operator++(int) noexcept { + auto tmp = *this; + Mybase::operator++(); + return tmp; + } + + disjoint_set_iterator& operator--() noexcept { + Mybase::operator--(); + return *this; + } + + disjoint_set_iterator operator--(int) noexcept { + auto tmp = *this; + Mybase::operator--(); + return tmp; + } + + [[nodiscard]] disjoint_set_iterator& operator+=(const difference_type off) noexcept { + Mybase::operator+=(off); + return *this; + } + + [[nodiscard]] disjoint_set_iterator operator+(const difference_type off) const noexcept { + auto tmp = *this; + tmp += off; + return tmp; + } + + [[nodiscard]] friend disjoint_set_iterator operator+( + const difference_type off, disjoint_set_iterator next) noexcept { + next += off; + return next; + } + + [[nodiscard]] disjoint_set_iterator& operator-=(const difference_type off) noexcept { + Mybase::operator-=(off); + return *this; + } + + [[nodiscard]] disjoint_set_iterator operator-(const difference_type off) const noexcept { + auto tmp = *this; + tmp -= off; + return tmp; + } + + [[nodiscard]] difference_type operator-(const disjoint_set_iterator& right) const noexcept { + return static_cast(this->parent - right.parent); + } + + [[nodiscard]] reference operator[](const difference_type off) const noexcept { + return const_cast(Mybase::operator[](off)); + } }; -#endif // USE_DISJOINT_SET_ITERATORS template class DisjointSet { // fixed size union find structure @@ -180,9 +290,9 @@ class DisjointSet { // fixed size union find structure rank.resize(size, 0); } -#ifdef USE_DISJOINT_SET_ITERATORS - using iterator = _Disjoint_set_iterator>; - using const_iterator = _Disjoint_set_const_iterator>; +#ifdef CPL + using iterator = disjoint_set_iterator>; + using const_iterator = disjoint_set_const_iterator>; [[nodiscard]] iterator begin() noexcept { return iterator(parent.begin(), rank.begin()); @@ -199,7 +309,7 @@ class DisjointSet { // fixed size union find structure [[nodiscard]] const_iterator end() const noexcept { return const_iterator(parent.end(), rank.end()); } -#endif // USE_DISJOINT_SET_ITERATORS +#endif // CPL private: std::vector parent; diff --git a/cpl/inc/xcore.h b/cpl/inc/xcore.h index e1f44ab..90b2852 100644 --- a/cpl/inc/xcore.h +++ b/cpl/inc/xcore.h @@ -23,8 +23,6 @@ // All macro library checks must first satisfy the `CPL` check. #define CPL 1 -#define USE_DISJOINT_SET_ITERATORS 1 - #undef CPL_STRINGIZE_ #undef CPL_STRINGIZE diff --git a/tests/cpl/disjoint_set/test.cpp b/tests/cpl/disjoint_set/test.cpp index 0c12d9d..619e605 100644 --- a/tests/cpl/disjoint_set/test.cpp +++ b/tests/cpl/disjoint_set/test.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MIT #include -#include #include "tree.h" @@ -45,6 +44,20 @@ int main() { assert(ds.find(i) == 0); } } + { + using CIt = DisjointSet::const_iterator; + + static_assert(std::random_access_iterator); + static_assert(std::same_as, std::pair>); + static_assert(std::same_as, std::ptrdiff_t>); + } + { + using CIt = DisjointSet::iterator; + + static_assert(std::random_access_iterator); + static_assert(std::same_as, std::pair>); + static_assert(std::same_as, std::ptrdiff_t>); + } { DisjointSet ds(5); ds.union_rank(0, 1);