From 480bddd36c2f9cd00f982fb6c9b197994bbf0ed2 Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Tue, 27 Feb 2024 21:14:45 +0900 Subject: [PATCH] 1.3.4 (#121) * Add common_iterator * Update variant.hpp * init common_view * Update variant.hpp * Add LOGXD * Create memory.hpp * Update logger.hpp * Fix common_iterator * Fix common_iterator * Update common_iterator.hpp * Add ranges::common_view, views::common * Add ranges::rbegin * Update rbegin * Update rbegin.hpp * Update rbegin.hpp * Add is_class_or_enum * Update not_incomplete_array.hpp * Add ranges::rend * Add ranges::reverse_view * Update reverse_view.hpp * Add is_subrange * Add views::reverse * Update ranges_test.cpp * Update ranges_test.cpp * Add ranges::join_with_view, views::join_with * Fix error * Update join_with_view.hpp * Add concat_view * Add concat_view * Update concat_view.hpp * Update concat_view.hpp * Update ranges_test.cpp * Update ranges_test.cpp * Fix views::split * Update concepts.hpp * Update concat_view.hpp * Update non_propagating_cache.hpp * Add drop_while_view, drop_while * Update drop_while_view.hpp * Update concat * Add tuple algorithm * Update concat_view.hpp * Update concat_view.hpp * Fix common_reference * Fix common_type * Move maybe_const * Update tuple_like.hpp * Add key, value * Add ranges:: lexicographical_compare * Fix hard error of indirectly_readable * Update basic_const_iterator.hpp * Support ranges for type_support * Fix unnecessary forwarding --- include/log/include/vccc/__log/logger.hpp | 8 +- .../include/vccc/__type_support/at.hpp | 2 +- .../__type_support/detail/container_at.hpp | 61 -- .../vccc/__type_support/detail/range_at.hpp | 37 ++ .../ranges/lexicographical_compare.hpp | 87 +++ .../vccc/__concepts/common_reference_with.hpp | 2 +- include/vccc/__concepts/swap.hpp | 5 +- .../vccc/__iterator/basic_const_iterator.hpp | 8 +- include/vccc/__iterator/common_iterator.hpp | 369 ++++++++++- .../vccc/__iterator/indirectly_readable.hpp | 2 +- include/vccc/__iterator/iter_move.hpp | 3 +- include/vccc/__iterator/iter_swap.hpp | 5 +- include/vccc/__ranges/begin.hpp | 4 +- include/vccc/__ranges/cbegin.hpp | 6 +- include/vccc/__ranges/cend.hpp | 6 +- include/vccc/__ranges/data.hpp | 4 +- .../__ranges/detail/not_incomplete_array.hpp | 26 + include/vccc/__ranges/distance.hpp | 2 +- include/vccc/__ranges/empty.hpp | 6 +- include/vccc/__ranges/end.hpp | 4 +- .../vccc/__ranges/non_propagating_cache.hpp | 2 +- include/vccc/__ranges/rbegin.hpp | 102 +++ include/vccc/__ranges/rend.hpp | 107 ++++ include/vccc/__ranges/size.hpp | 6 +- include/vccc/__ranges/ssize.hpp | 4 +- include/vccc/__ranges/subrange.hpp | 5 + .../__ranges/views/cartesian_product_view.hpp | 42 +- include/vccc/__ranges/views/common.hpp | 56 ++ include/vccc/__ranges/views/common_view.hpp | 127 ++++ include/vccc/__ranges/views/concat_view.hpp | 494 ++++++++++++++ .../vccc/__ranges/views/concat_with_view.hpp | 495 +++++++++++++++ include/vccc/__ranges/views/drop.hpp | 15 +- include/vccc/__ranges/views/drop_while.hpp | 63 ++ .../vccc/__ranges/views/drop_while_view.hpp | 99 +++ include/vccc/__ranges/views/elements_view.hpp | 18 +- include/vccc/__ranges/views/enumerate.hpp | 14 +- .../vccc/__ranges/views/enumerate_view.hpp | 26 +- include/vccc/__ranges/views/join_view.hpp | 14 +- include/vccc/__ranges/views/join_with.hpp | 83 +++ .../vccc/__ranges/views/join_with_view.hpp | 601 ++++++++++++++++++ include/vccc/__ranges/views/maybe_const.hpp | 21 - include/vccc/__ranges/views/reverse.hpp | 82 +++ include/vccc/__ranges/views/reverse_view.hpp | 133 ++++ include/vccc/__ranges/views/split.hpp | 15 +- include/vccc/__ranges/views/take.hpp | 17 +- include/vccc/__ranges/views/take_view.hpp | 8 +- include/vccc/__ranges/views/views.hpp | 9 + include/vccc/__span/span.hpp | 8 +- include/vccc/__tuple/common_type.hpp | 58 -- include/vccc/__tuple/detail/apply.hpp | 2 +- include/vccc/__tuple/tuple_fold.hpp | 65 ++ include/vccc/__tuple/tuple_like.hpp | 30 +- include/vccc/__tuple/tuple_transform.hpp | 40 ++ include/vccc/__type_traits/common_type.hpp | 86 ++- .../vccc/__type_traits/is_class_or_enum.hpp | 27 + include/vccc/__type_traits/maybe_const.hpp | 17 + include/vccc/__utility/key_value.hpp | 44 ++ include/vccc/__utility/type_sequence.hpp | 3 + include/vccc/__variant/variant.hpp | 9 + include/vccc/algorithm.hpp | 1 + include/vccc/concepts.hpp | 1 + include/vccc/iterator.hpp | 1 + include/vccc/memory.hpp | 11 + include/vccc/ranges.hpp | 2 + include/vccc/tuple.hpp | 3 +- include/vccc/type_traits.hpp | 2 + include/vccc/utility.hpp | 1 + test/algorithm_test.cpp | 12 + test/ranges_test.cpp | 271 +++++++- test/tuple_test.cpp | 20 + 70 files changed, 3732 insertions(+), 287 deletions(-) delete mode 100644 include/type_support/include/vccc/__type_support/detail/container_at.hpp create mode 100644 include/type_support/include/vccc/__type_support/detail/range_at.hpp create mode 100644 include/vccc/__algorithm/ranges/lexicographical_compare.hpp create mode 100644 include/vccc/__ranges/detail/not_incomplete_array.hpp create mode 100644 include/vccc/__ranges/rbegin.hpp create mode 100644 include/vccc/__ranges/rend.hpp create mode 100644 include/vccc/__ranges/views/common.hpp create mode 100644 include/vccc/__ranges/views/common_view.hpp create mode 100644 include/vccc/__ranges/views/concat_view.hpp create mode 100644 include/vccc/__ranges/views/concat_with_view.hpp create mode 100644 include/vccc/__ranges/views/drop_while.hpp create mode 100644 include/vccc/__ranges/views/drop_while_view.hpp create mode 100644 include/vccc/__ranges/views/join_with.hpp create mode 100644 include/vccc/__ranges/views/join_with_view.hpp delete mode 100644 include/vccc/__ranges/views/maybe_const.hpp create mode 100644 include/vccc/__ranges/views/reverse.hpp create mode 100644 include/vccc/__ranges/views/reverse_view.hpp delete mode 100644 include/vccc/__tuple/common_type.hpp create mode 100644 include/vccc/__tuple/tuple_fold.hpp create mode 100644 include/vccc/__tuple/tuple_transform.hpp create mode 100644 include/vccc/__type_traits/is_class_or_enum.hpp create mode 100644 include/vccc/__type_traits/maybe_const.hpp create mode 100644 include/vccc/__utility/key_value.hpp create mode 100644 include/vccc/memory.hpp diff --git a/include/log/include/vccc/__log/logger.hpp b/include/log/include/vccc/__log/logger.hpp index f7ecdb56..ce97e293 100644 --- a/include/log/include/vccc/__log/logger.hpp +++ b/include/log/include/vccc/__log/logger.hpp @@ -97,11 +97,14 @@ class Logger { */ constexpr Logger Log; -/// @defgroup log_log_macro__macro__Logging_macros LOGD, LOGI, LOGW, LOGE +/// @defgroup log_log_macro__macro__Logging_macros LOGD, LOGI, LOGID, LOGW, LOGWD, LOGE, LOGED /// @{ # ifdef NDEBUG # define LOGD(...) +# define LOGID(...) +# define LOGWD(...) +# define LOGED(...) #else /** * @@ -115,6 +118,9 @@ Below example applies to LOGI, LOGW, LOGE @endcode */ # define LOGD(...) ::vccc::Log.d(__VA_ARGS__) +# define LOGID(...) ::vccc::Log.i(__VA_ARGS__) +# define LOGWD(...) ::vccc::Log.w(__VA_ARGS__) +# define LOGED(...) ::vccc::Log.e(__VA_ARGS__) # endif /** @brief Information log wrapper **/ diff --git a/include/type_support/include/vccc/__type_support/at.hpp b/include/type_support/include/vccc/__type_support/at.hpp index 654d1714..9e0a6a15 100644 --- a/include/type_support/include/vccc/__type_support/at.hpp +++ b/include/type_support/include/vccc/__type_support/at.hpp @@ -5,7 +5,7 @@ # ifndef VCCC_TYPE_SUPPORT_AT_HPP # define VCCC_TYPE_SUPPORT_AT_HPP # -# include "vccc/__type_support/detail/container_at.hpp" +# include "vccc/__type_support/detail/range_at.hpp" # include "vccc/__type_support/core.hpp" # include "vccc/__type_support/cast.hpp" # include "vccc/type_traits.hpp" diff --git a/include/type_support/include/vccc/__type_support/detail/container_at.hpp b/include/type_support/include/vccc/__type_support/detail/container_at.hpp deleted file mode 100644 index d97b055f..00000000 --- a/include/type_support/include/vccc/__type_support/detail/container_at.hpp +++ /dev/null @@ -1,61 +0,0 @@ -# /* -# * Created by YongGyu Lee on 2020/12/08. -# */ -# -# ifndef VCCC_TYPE_SUPPORT_DETAIL_CONTAINER_AT_HPP -# define VCCC_TYPE_SUPPORT_DETAIL_CONTAINER_AT_HPP -# -# include -# include -# -# include "vccc/type_traits.hpp" -# include "vccc/utility.hpp" - -namespace vccc { - -/** -@addtogroup type_support_at__func -@{ -@defgroup type_support_at_container__func vccc::at (container) -Index-based value accessor - -@{ -*/ -template::value, int> = 0> -decltype(auto) -at(Container& container) -{ - BOUNDS_ASSERT(i, container.size()); - return *std::next(std::begin(container), i); -} - -template::value, int> = 0> -decltype(auto) -at(const Container& container) -{ - BOUNDS_ASSERT(i, container.size()); - return *std::next(std::begin(container), i); -} - -template::value, int> = 0> -decltype(auto) -at(Container&& container) -{ - BOUNDS_ASSERT(i, container.size()); - return std::move(*std::next(std::begin(container), i)); -} - -template::value, int> = 0> -decltype(auto) -at(const Container&& container) -{ - BOUNDS_ASSERT(i, container.size()); - return std::move(*std::next(std::begin(container), i)); -} - -//! @} -//! @} type_support - -} - -# endif // VCCC_TYPE_SUPPORT_DETAIL_CONTAINER_AT_HPP diff --git a/include/type_support/include/vccc/__type_support/detail/range_at.hpp b/include/type_support/include/vccc/__type_support/detail/range_at.hpp new file mode 100644 index 00000000..54fd5d71 --- /dev/null +++ b/include/type_support/include/vccc/__type_support/detail/range_at.hpp @@ -0,0 +1,37 @@ +# /* +# * Created by YongGyu Lee on 2020/12/08. +# */ +# +# ifndef VCCC_TYPE_SUPPORT_DETAIL_RANGE_AT_HPP +# define VCCC_TYPE_SUPPORT_DETAIL_RANGE_AT_HPP +# +# include +# include +# +# include "vccc/ranges.hpp" +# include "vccc/utility.hpp" + +namespace vccc { + +/** +@addtogroup type_support_at__func +@{ +@defgroup type_support_at_container__func vccc::at (container) +Index-based value accessor + +@{ +*/ +template::value, int> = 0> +decltype(auto) +at(R&& container) +{ + BOUNDS_ASSERT(i, ranges::distance(container)); + return *ranges::next(ranges::begin(container), i); +} + +//! @} +//! @} type_support + +} + +# endif // VCCC_TYPE_SUPPORT_DETAIL_RANGE_AT_HPP diff --git a/include/vccc/__algorithm/ranges/lexicographical_compare.hpp b/include/vccc/__algorithm/ranges/lexicographical_compare.hpp new file mode 100644 index 00000000..63f5a89b --- /dev/null +++ b/include/vccc/__algorithm/ranges/lexicographical_compare.hpp @@ -0,0 +1,87 @@ +// +// Created by YongGyu Lee on 2/24/24. +// + +#ifndef VCCC_ALGORITHM_RANGES_LEXICOGRAPHICAL_COMPARE_HPP +#define VCCC_ALGORITHM_RANGES_LEXICOGRAPHICAL_COMPARE_HPP + +#include +#include + +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__functional/identity.hpp" +#include "vccc/__functional/invoke.hpp" +#include "vccc/__functional/less.hpp" +#include "vccc/__iterator/indirect_strict_weak_order.hpp" +#include "vccc/__iterator/input_iterator.hpp" +#include "vccc/__iterator/projected.hpp" +#include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__utility/cxx20_rel_ops.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +struct lexicographical_compare_niebloid { + private: + template, projectable>::value /* false_type */> + struct test_projectable_iterator : std::false_type {}; + template + struct test_projectable_iterator + : indirect_strict_weak_order, projected> {}; + + template, input_range>::value /* false_type */> + struct test_projectable_range : std::false_type {}; + template + struct test_projectable_range + : test_projectable_iterator, Proj1, iterator_t, Proj2, Comp> {}; + + public: + template< + typename I1, typename S1, + typename I2, typename S2, + typename Proj1 = identity, typename Proj2 = identity, typename Comp = ranges::less, + std::enable_if_t, sentinel_for, + input_iterator, sentinel_for, + test_projectable_iterator + >::value, int> = 0 + > + constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { + using namespace rel_ops; + for (; (first1 != last1) && (first2 != last2); ++first1, (void) ++first2) { + if (vccc::invoke(comp, vccc::invoke(proj1, *first1), vccc::invoke(proj2, *first2))) + return true; + if (vccc::invoke(comp, vccc::invoke(proj2, *first2), vccc::invoke(proj1, *first1))) + return false; + } + return (first1 == last1) && (first2 != last2); + } + + template + ::value, int> = 0> + constexpr bool operator()(R1&& r1, R2&& r2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { + return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), std::ref(comp), std::ref(proj1), std::ref(proj2)); + } + +}; + +} // namespace detail + +/// @addtogroup algorithm +/// @{ + +/// @brief returns `true` if one range is lexicographically less than another +VCCC_INLINE_OR_STATIC constexpr detail::lexicographical_compare_niebloid lexicographical_compare{}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_ALGORITHM_RANGES_LEXICOGRAPHICAL_COMPARE_HPP diff --git a/include/vccc/__concepts/common_reference_with.hpp b/include/vccc/__concepts/common_reference_with.hpp index 8e69e433..da5cc3a8 100644 --- a/include/vccc/__concepts/common_reference_with.hpp +++ b/include/vccc/__concepts/common_reference_with.hpp @@ -21,7 +21,7 @@ template< typename U, bool = conjunction< has_typename_type>, - has_typename_type> + has_typename_type> >::value /* false */ > struct common_reference_with_impl : std::false_type {}; diff --git a/include/vccc/__concepts/swap.hpp b/include/vccc/__concepts/swap.hpp index 51145886..dd51ec29 100644 --- a/include/vccc/__concepts/swap.hpp +++ b/include/vccc/__concepts/swap.hpp @@ -15,6 +15,7 @@ #include "vccc/__type_traits/conjunction.hpp" #include "vccc/__type_traits/disjunction.hpp" #include "vccc/__type_traits/negation.hpp" +#include "vccc/__type_traits/is_class_or_enum.hpp" namespace vccc { namespace ranges { @@ -32,8 +33,8 @@ template constexpr auto test_swap(...) -> std::false_type; template>, std::is_enum>, - std::is_class>, std::is_enum> >::value> + is_class_or_enum>, + is_class_or_enum>>::value> struct adl_swappable : std::false_type {}; template diff --git a/include/vccc/__iterator/basic_const_iterator.hpp b/include/vccc/__iterator/basic_const_iterator.hpp index fbdfbef9..3a9df09f 100644 --- a/include/vccc/__iterator/basic_const_iterator.hpp +++ b/include/vccc/__iterator/basic_const_iterator.hpp @@ -47,7 +47,11 @@ struct basic_const_iterator_category { }; template -struct basic_const_iterator_category {}; +struct basic_const_iterator_category { +#if __cplusplus < 202002L + using iterator_category = iterator_ignore; +#endif +}; template struct basic_const_iterator_concept { @@ -89,7 +93,6 @@ struct const_iterator_implicit_conversion_check template class basic_const_iterator : public detail::basic_const_iterator_category { - using reference = iter_const_reference_t; using rvalue_reference = common_reference_t&&, iter_rvalue_reference_t>; public: static_assert(input_iterator::value, "Constraints not satisfied"); @@ -97,6 +100,7 @@ class basic_const_iterator : public detail::basic_const_iterator_category using iterator_concept = typename detail::basic_const_iterator_concept::iterator_concept; using value_type = iter_value_t; using difference_type = iter_difference_t; + using reference = iter_const_reference_t; basic_const_iterator() = default; diff --git a/include/vccc/__iterator/common_iterator.hpp b/include/vccc/__iterator/common_iterator.hpp index 70b2bb23..2397b73d 100644 --- a/include/vccc/__iterator/common_iterator.hpp +++ b/include/vccc/__iterator/common_iterator.hpp @@ -5,32 +5,377 @@ #ifndef VCCC_ITERATOR_COMMON_ITERATOR_HPP_ #define VCCC_ITERATOR_COMMON_ITERATOR_HPP_ +#include #include +#include +#include "vccc/__concepts/constructible_from.hpp" +#include "vccc/__concepts/convertible_to.hpp" #include "vccc/__concepts/copyable.hpp" +#include "vccc/__concepts/dereferenceable.hpp" +#include "vccc/__concepts/derived_from.hpp" +#include "vccc/__concepts/different_from.hpp" +#include "vccc/__concepts/equality_comparable.hpp" +#include "vccc/__concepts/move_constructible.hpp" #include "vccc/__concepts/same_as.hpp" +#include "vccc/__iterator/forward_iterator.hpp" +#include "vccc/__iterator/incrementable_traits.hpp" +#include "vccc/__iterator/indirectly_readable.hpp" #include "vccc/__iterator/input_or_output_iterator.hpp" +#include "vccc/__iterator/iterator_tag.hpp" +#include "vccc/__iterator/iterator_traits/cxx20_iterator_traits.hpp" #include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__iterator/weakly_incrementable.hpp" +#include "vccc/__memory/addressof.hpp" #include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/detail/tag.hpp" +#include "vccc/__type_traits/has_operator_arrow.hpp" #include "vccc/__type_traits/negation.hpp" +#include "vccc/__utility/cxx20_rel_ops.hpp" +#include "vccc/__utility/in_place.hpp" +#include "vccc/variant.hpp" namespace vccc { -// TODO: Implement variant -// template -// class common_iterator { -// public: -// static_assert(input_or_output_iterator::value, "Constraints not satisfied"); -// static_assert(sentinel_for::value, "Constraints not satisfied"); -// static_assert(negation>::value, "Constraints not satisfied"); -// static_assert(copyable::value, "Constraints not satisfied"); -// -// -// private: -// }; +template +class common_iterator { + class proxy { + friend class common_iterator; + + iter_value_t keep_; + constexpr proxy(iter_reference_t&& x) + : keep_(std::forward>(x)) {} + + public: + constexpr const iter_value_t* operator->() const noexcept { + return vccc::addressof(keep_); + } + + }; + + class postfix_proxy { + friend class common_iterator; + + iter_value_t keep_; + constexpr postfix_proxy(iter_reference_t&& x) + : keep_(std::forward>(x)) {} + + public: + constexpr const iter_value_t& operator*() const noexcept { + return keep_; + } + }; + + public: + static_assert(input_or_output_iterator::value, "Constraints not satisfied"); + static_assert(sentinel_for::value, "Constraints not satisfied"); + static_assert(negation>::value, "Constraints not satisfied"); + static_assert(copyable::value, "Constraints not satisfied"); + + common_iterator() = default; + + constexpr common_iterator(I i) : var_(std::move(i)) {} + constexpr common_iterator(S s) : var_(std::move(s)) {} + + template, + convertible_to + >::value, int> = 0> + constexpr common_iterator(const common_iterator& x) + noexcept(conjunction< + std::is_nothrow_constructible, + std::is_nothrow_constructible>::value) + : var_{detail::variant_valueless_ctor{}} + { + switch (x.var_.index()) { + case 0: + var_.emplace<0>(detail::variant_raw_get(x.var_._base().storage(), in_place_index<0>)); + break; + case 1: + var_.emplace<1>(detail::variant_raw_get(x.var_._base().storage(), in_place_index<1>)); + break; + default: + break; + } + } + + template + constexpr common_iterator& operator=(const common_iterator& x) + noexcept(conjunction< + std::is_nothrow_constructible, std::is_nothrow_assignable, + std::is_nothrow_constructible, std::is_nothrow_assignable >::value) + { + if (var_.index() == x.var_.index()) { + switch (x.var_.index()) { + case 0: + this->iterator() = detail::variant_raw_get(x.var_._base().storage(), in_place_index<0>); + return *this; + case 1: + this->sentinel() = detail::variant_raw_get(x.var_._base().storage(), in_place_index<1>); + return *this; + default: + break; + } + } + + switch (x.var_.index()) { + case 0: + var_.emplace<0>(detail::variant_raw_get(x._base().storage(), in_place_index<0>)); + break; + case 1: + var_.emplace<1>(detail::variant_raw_get(x._base().storage(), in_place_index<1>)); + break; + default: + break; + } + + return *this; + } + + constexpr decltype(auto) operator*() { + return *this->iterator(); + } + + template::value, int> = 0> + constexpr decltype(auto) operator*() const { + return *this->iterator(); + } + + template, + disjunction< + std::is_pointer, + has_operator_arrow, + std::is_reference>, + constructible_from, iter_reference_t> + > + >::value, int> = 0> + constexpr auto operator->() const { + using tag = + detail::conditional_tag< + disjunction, has_operator_arrow>, + std::is_reference> + >; + return operator_arrow(tag{}); + } + + constexpr common_iterator& operator++() { + ++this->iterator(); + return *this; + } + + constexpr decltype(auto) operator++(int) { + using tag = + detail::conditional_tag< + forward_iterator, + disjunction< + conjunction< + detail::is_post_incrementable, + dereferenceable + >, + negation< indirectly_readable >, + negation< constructible_from, iter_reference_t> >, + negation< move_constructible> > + > + >; + return post_increment(tag{}); + } + template, + sentinel_for, + negation< equality_comparable_with > + >::value, int> = 0> + friend constexpr bool operator==(const common_iterator& x, const common_iterator& y) { + if (x.var_.index() == y.var_.index()) + return true; + using namespace vccc::rel_ops; + switch (x.var_.index()) { + case 0: + switch(y.var_.index()) { + case 0: return true; + case 1: return x.iterator() == y.sentinel(); + default: return false; + } + case 1: + switch(y.var_.index()) { + case 0: return x.sentinel() == y.iterator(); + case 1: return true; + default: return false; + } + default: + return false; + } + } + + template, + sentinel_for, + negation< equality_comparable_with > + >::value, int> = 0> + friend constexpr bool operator!=(const common_iterator& x, const common_iterator& y) { + return !(x == y); + } + + template, + sentinel_for, + equality_comparable_with + >::value, int> = 0> + friend constexpr bool operator==(const common_iterator& x, const common_iterator& y) { + using namespace vccc::rel_ops; + switch (x.var_.index()) { + case 0: + switch(y.var_.index()) { + case 0: return x.iterator() == y.iterator(); + case 1: return x.iterator() == y.sentinel(); + default: return false; + } + case 1: + switch(y.var_.index()) { + case 0: return x.sentinel() == y.iterator(); + case 1: return true; + default: return false; + } + default: + return false; + } + } + + template, + sentinel_for, + equality_comparable_with + >::value, int> = 0> + friend constexpr bool operator!=(const common_iterator& x, const common_iterator& y) { + return !(x == y); + } + + + template, + sized_sentinel_for, + sentinel_for + >::value, int> = 0> + friend constexpr iter_difference_t operator-(const common_iterator& x, const common_iterator& y) { + switch (x.var_.index()) { + case 0: + switch(y.var_.index()) { + case 0: return x.iterator() - y.iterator(); + case 1: return x.iterator() - y.sentinel(); + default: return 0; + } + case 1: + switch(y.var_.index()) { + case 0: return x.sentinel() - y.iterator(); + case 1: return 0; + default: return 0; + } + default: + return 0; + } + } + + private: + decltype(auto) iterator() { + return detail::variant_raw_get(var_._base().storage(), in_place_index<0>); + } + decltype(auto) iterator() const { + return detail::variant_raw_get(var_._base().storage(), in_place_index<0>); + } + decltype(auto) sentinel() { + return detail::variant_raw_get(var_._base().storage(), in_place_index<1>); + } + decltype(auto) sentinel() const { + return detail::variant_raw_get(var_._base().storage(), in_place_index<1>); + } + + constexpr auto operator_arrow(detail::tag_1) const { + return this->iterator(); + } + constexpr auto operator_arrow(detail::tag_2) const { + auto&& tmp = **this; + return vccc::addressof(tmp); + } + constexpr auto operator_arrow(detail::tag_else) const { + return proxy(**this); + } + + constexpr decltype(auto) post_increment(detail::tag_1) { + auto tmp = *this; + ++*this; + return tmp; + } + constexpr decltype(auto) post_increment(detail::tag_2) { + return this->iterator()++; + } + constexpr postfix_proxy post_increment(detail::tag_else) { + postfix_proxy p(**this); + ++*this; + return p; + } + + variant var_{}; +}; + +template +struct incrementable_traits> { + using difference_type = iter_difference_t; +}; + +namespace detail { + +template>::value /* false */> +struct common_iterator_category { +#if __cplusplus < 202002L + using iterator_category = iterator_ignore; +#endif +}; + +template>::value /* false */> +struct common_iterator_category_check_forward : std::false_type {}; +template +struct common_iterator_category_check_forward + : derived_from::iterator_category, forward_iterator_tag> {}; + +template +struct common_iterator_category { + using iterator_category = + std::conditional_t< + common_iterator_category_check_forward::value, + forward_iterator_tag, + input_iterator_tag + >; +}; + +template&>::value /* false */> +struct common_iterator_pointer { + using type = void; +}; +template +struct common_iterator_pointer { + using type = decltype(std::declval&>().operator->()); +}; + +} // namespace detail + +template +struct cxx20_iterator_traits> : detail::common_iterator_category { + using iterator_concept = std::conditional_t::value, forward_iterator_tag, input_iterator_tag>; + using value_type = iter_value_t; + using difference_type = iter_difference_t; + using pointer = typename detail::common_iterator_pointer::type; + using reference = iter_reference_t; +}; + +template +struct detail::is_primary_iterator_traits< cxx20_iterator_traits> > : std::false_type {}; } // namespace vccc +template +struct std::iterator_traits<::vccc::common_iterator> + : ::vccc::cxx20_iterator_traits<::vccc::common_iterator> {}; + #endif // VCCC_ITERATOR_COMMON_ITERATOR_HPP_ diff --git a/include/vccc/__iterator/indirectly_readable.hpp b/include/vccc/__iterator/indirectly_readable.hpp index 22f218f6..6543c142 100644 --- a/include/vccc/__iterator/indirectly_readable.hpp +++ b/include/vccc/__iterator/indirectly_readable.hpp @@ -34,7 +34,7 @@ struct indirectly_readable_impl template< typename In, bool = conjunction< - dereferenceable, + dereferenceable, has_typename_type>, has_typename_type>, has_typename_type> diff --git a/include/vccc/__iterator/iter_move.hpp b/include/vccc/__iterator/iter_move.hpp index 1f3b396b..8559b2b2 100644 --- a/include/vccc/__iterator/iter_move.hpp +++ b/include/vccc/__iterator/iter_move.hpp @@ -13,6 +13,7 @@ #include "vccc/__type_traits/detail/return_category.hpp" #include "vccc/__type_traits/conjunction.hpp" #include "vccc/__type_traits/disjunction.hpp" +#include "vccc/__type_traits/is_class_or_enum.hpp" namespace vccc { namespace ranges { @@ -22,7 +23,7 @@ using vccc::detail::return_category; template< typename T, - bool = disjunction>, std::is_enum>>::value, + bool = is_class_or_enum>::value, typename = void > struct iter_move_check_adaptors : std::false_type { diff --git a/include/vccc/__iterator/iter_swap.hpp b/include/vccc/__iterator/iter_swap.hpp index 45abfaa9..44816c4c 100644 --- a/include/vccc/__iterator/iter_swap.hpp +++ b/include/vccc/__iterator/iter_swap.hpp @@ -19,6 +19,7 @@ #include "vccc/__type_traits/disjunction.hpp" #include "vccc/__type_traits/negation.hpp" #include "vccc/__type_traits/remove_cvref.hpp" +#include "vccc/__type_traits/is_class_or_enum.hpp" namespace vccc { namespace ranges { @@ -34,8 +35,8 @@ template constexpr auto test_iter_swap(...) -> std::false_type; template>, std::is_enum>, - std::is_class>, std::is_enum> + is_class_or_enum>, + is_class_or_enum> >::value> struct unqual_iter_swap : decltype(test_iter_swap(0)) {}; diff --git a/include/vccc/__ranges/begin.hpp b/include/vccc/__ranges/begin.hpp index be6b5314..be753313 100644 --- a/include/vccc/__ranges/begin.hpp +++ b/include/vccc/__ranges/begin.hpp @@ -82,12 +82,12 @@ constexpr R ranges_begin(T&& t, return_category<1, R>) { template constexpr R ranges_begin(T&& t, return_category<2, R>) { - return vccc_decay_copy(std::forward(t).begin()); + return vccc_decay_copy(t.begin()); } template constexpr R ranges_begin(T&& t, return_category<3, R>) { - return vccc_decay_copy(begin(std::forward(t))); + return vccc_decay_copy(begin(t)); } struct begin_niebloid { diff --git a/include/vccc/__ranges/cbegin.hpp b/include/vccc/__ranges/cbegin.hpp index ea4a89c1..46f87372 100644 --- a/include/vccc/__ranges/cbegin.hpp +++ b/include/vccc/__ranges/cbegin.hpp @@ -33,15 +33,15 @@ struct cbegin_niebloid { private: template constexpr auto call(T&& t, vccc::detail::tag_1) const { - return ranges::begin(std::forward(t)); + return ranges::begin(t); } template constexpr auto call(T&& t, vccc::detail::tag_2) const { - return ranges::begin(vccc::as_const(std::forward(t))); + return ranges::begin(vccc::as_const(t)); } template constexpr auto call(T&& t, vccc::detail::tag_else) const { - return make_const_iterator(ranges::begin(std::forward(t))); + return make_const_iterator(ranges::begin(t)); } }; diff --git a/include/vccc/__ranges/cend.hpp b/include/vccc/__ranges/cend.hpp index 32df0f4b..4b3343d2 100644 --- a/include/vccc/__ranges/cend.hpp +++ b/include/vccc/__ranges/cend.hpp @@ -33,15 +33,15 @@ struct cend_niebloid { private: template constexpr auto call(T&& t, vccc::detail::tag_1) const { - return ranges::end(std::forward(t)); + return ranges::end(t); } template constexpr auto call(T&& t, vccc::detail::tag_2) const { - return ranges::end(vccc::as_const(std::forward(t))); + return ranges::end(vccc::as_const(t)); } template constexpr auto call(T&& t, vccc::detail::tag_else) const { - return make_const_sentinel(ranges::end(std::forward(t))); + return make_const_sentinel(ranges::end(t)); } }; diff --git a/include/vccc/__ranges/data.hpp b/include/vccc/__ranges/data.hpp index c7f685f6..346ef0be 100644 --- a/include/vccc/__ranges/data.hpp +++ b/include/vccc/__ranges/data.hpp @@ -73,12 +73,12 @@ struct data_niebloid { private: template constexpr R operator()(T&& t, return_category<1, R>) const { - return vccc_decay_copy(std::forward(t).data()); + return vccc_decay_copy(t.data()); } template constexpr R operator()(T&& t, return_category<2, R>) const { - return vccc::to_address(ranges::begin(std::forward(t))); + return vccc::to_address(ranges::begin(t)); } }; diff --git a/include/vccc/__ranges/detail/not_incomplete_array.hpp b/include/vccc/__ranges/detail/not_incomplete_array.hpp new file mode 100644 index 00000000..fde45652 --- /dev/null +++ b/include/vccc/__ranges/detail/not_incomplete_array.hpp @@ -0,0 +1,26 @@ +// +// Created by YongGyu Lee on 2/8/24. +// + +#ifndef VCCC_RANGES_DETAIL_NOT_INCOMPLETE_ARRAY_HPP_ +#define VCCC_RANGES_DETAIL_NOT_INCOMPLETE_ARRAY_HPP_ + +#include + +#include "vccc/__type_traits/is_complete.hpp" +#include "vccc/__type_traits/remove_cvref.hpp" + +namespace vccc { +namespace detail { + +template>::value /* false */> +struct not_incomplete_array : std::true_type {}; + +template +struct not_incomplete_array + : is_complete>> {}; + +} // namespace detail +} // namespace vccc + +#endif // VCCC_RANGES_DETAIL_NOT_INCOMPLETE_ARRAY_HPP_ diff --git a/include/vccc/__ranges/distance.hpp b/include/vccc/__ranges/distance.hpp index 8e6dec42..15143f0f 100644 --- a/include/vccc/__ranges/distance.hpp +++ b/include/vccc/__ranges/distance.hpp @@ -49,7 +49,7 @@ struct distance_niebloid { template>::value, int> = 0> constexpr ranges::range_difference_t operator()(R&& r) const { - return static_cast>(ranges::size(std::forward(r))); + return static_cast>(ranges::size(r)); } template constexpr R empty_impl(T&& t, return_category<1, R>) { - return bool(std::forward(t).empty()); + return bool(t.empty()); } template constexpr R empty_impl(T&& t, return_category<2, R>) { - return (ranges::size(std::forward(t)) == 0); + return (ranges::size(t) == 0); } template constexpr R empty_impl(T&& t, return_category<3, R>) { using namespace vccc::rel_ops; - return bool(ranges::begin(std::forward(t)) == ranges::end(std::forward(t))); + return bool(ranges::begin(t) == ranges::end(t)); } struct empty_niebloid { diff --git a/include/vccc/__ranges/end.hpp b/include/vccc/__ranges/end.hpp index de948691..f2ed991c 100644 --- a/include/vccc/__ranges/end.hpp +++ b/include/vccc/__ranges/end.hpp @@ -86,12 +86,12 @@ struct end_niebloid { template constexpr R operator()(T&& t, return_category<2, R>) const { - return vccc_decay_copy(std::forward(t).end()); + return vccc_decay_copy(t.end()); } template constexpr R operator()(T&& t, return_category<3, R>) const { - return vccc_decay_copy(end(std::forward(t))); + return vccc_decay_copy(end(t)); } public: diff --git a/include/vccc/__ranges/non_propagating_cache.hpp b/include/vccc/__ranges/non_propagating_cache.hpp index edbd9f67..d0e113a5 100644 --- a/include/vccc/__ranges/non_propagating_cache.hpp +++ b/include/vccc/__ranges/non_propagating_cache.hpp @@ -26,7 +26,7 @@ struct constructible_from_deref : constructible_from -class non_propagating_cache : public optional { +class non_propagating_cache : private optional { using base = optional; public: static_assert(std::is_object::value, "Constraints not satisfied"); diff --git a/include/vccc/__ranges/rbegin.hpp b/include/vccc/__ranges/rbegin.hpp new file mode 100644 index 00000000..6dc7859a --- /dev/null +++ b/include/vccc/__ranges/rbegin.hpp @@ -0,0 +1,102 @@ +// +// Created by yonggyulee on 2024/02/08. +// + +#ifndef VCCC_RANGES_RBEGIN_HPP_ +#define VCCC_RANGES_RBEGIN_HPP_ + +#include +#include + +#include "vccc/__core/decay_copy.hpp" +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__iterator/input_or_output_iterator.hpp" +#include "vccc/__iterator/forward_iterator.hpp" +#include "vccc/__ranges/common_range.hpp" +#include "vccc/__ranges/detail/not_incomplete_array.hpp" +#include "vccc/__ranges/enable_borrowed_range.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__type_traits/bool_constant.hpp" +#include "vccc/__type_traits/detail/tag.hpp" +#include "vccc/__type_traits/disjunction.hpp" +#include "vccc/__type_traits/is_class_or_enum.hpp" +#include "vccc/__type_traits/remove_cvref.hpp" +#include "vccc/__type_traits/void_t.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +using vccc::detail::tag_1; +using vccc::detail::tag_2; +using vccc::detail::tag_3; + +struct rbegin_niebloid { + private: + + template + struct rbegin_member_check : std::false_type {}; + template + struct rbegin_member_check().rbegin() )) >> + : input_or_output_iterator().rbegin() )) > {}; + + template>::value, typename = void> + struct rbegin_global_check : std::false_type {}; + template + struct rbegin_global_check()) ))>> + : input_or_output_iterator()) ))> {}; + + template::value> + struct common_bidi_check : std::false_type {}; + template + struct common_bidi_check : bidirectional_iterator()) )> {}; + + template + using rbegin_tag = conditional_tag, rbegin_global_check, common_bidi_check>; + + template + constexpr auto run(T&& t, tag_1) const { + return vccc_decay_copy(t.rbegin()); + } + + template + constexpr auto run(T&& t, tag_2) const { + return vccc_decay_copy(rbegin(t)); + } + + template + constexpr auto run(T&& t, tag_3) const { + return std::make_reverse_iterator(ranges::end(t)); + } + + public: + template, + disjunction< + std::is_lvalue_reference>, + enable_borrowed_range> + >, + bool_constant<(rbegin_tag::value > 0)> + >::value, int> = 0> + constexpr auto operator()(T&& t) const { + return run(std::forward(t), rbegin_tag{}); + } +}; + +} // namespace detail + +inline namespace niebloid { + +/// @addtogroup ranges +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::rbegin_niebloid rbegin{}; + +/// @} + +} // inline namespace niebloid + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_RBEGIN_HPP_ diff --git a/include/vccc/__ranges/rend.hpp b/include/vccc/__ranges/rend.hpp new file mode 100644 index 00000000..21301bcf --- /dev/null +++ b/include/vccc/__ranges/rend.hpp @@ -0,0 +1,107 @@ +// +// Created by yonggyulee on 2024/02/08. +// + +#ifndef VCCC_RANGES_REND_HPP_ +#define VCCC_RANGES_REND_HPP_ + +#include +#include + +#include "vccc/__core/decay_copy.hpp" +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__iterator/bidirectional_iterator.hpp" +#include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__ranges/common_range.hpp" +#include "vccc/__ranges/enable_borrowed_range.hpp" +#include "vccc/__ranges/detail/not_incomplete_array.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/rbegin.hpp" +#include "vccc/__type_traits/disjunction.hpp" +#include "vccc/__type_traits/is_invocable.hpp" +#include "vccc/__type_traits/remove_cvref.hpp" +#include "vccc/__type_traits/void_t.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +using vccc::detail::tag_1; +using vccc::detail::tag_2; +using vccc::detail::tag_3; + +struct rend_niebloid { + private: + + template::value, typename = void> + struct rend_member_check : std::false_type {}; + template + struct rend_member_check().rend() ))>> + : sentinel_for().rend() )), + decltype( ranges::rbegin(std::declval()) )> {}; + + template, + is_class_or_enum>>::value, typename = void> + struct rend_global_check : std::false_type {}; + template + struct rend_global_check()) ))>> + : sentinel_for()) )), + decltype( ranges::rbegin(std::declval()) )> {}; + + template::value> + struct common_bidi_check : std::false_type {}; + template + struct common_bidi_check : bidirectional_iterator()) )> {}; + + template + using rend_tag = conditional_tag, rend_global_check, common_bidi_check>; + + template + constexpr auto run(T&& t, tag_1) const { + return vccc_decay_copy(t.rend()); + } + + template + constexpr auto run(T&& t, tag_2) const { + return vccc_decay_copy(rend(t)); + } + + template + constexpr auto run(T&& t, tag_3) const { + return std::make_reverse_iterator(ranges::begin(t)); + } + + public: + template, + disjunction< + std::is_lvalue_reference>, + enable_borrowed_range> + >, + bool_constant<(rend_tag::value > 0)> + >::value, int> = 0> + constexpr auto operator()(T&& t) const { + return run(std::forward(t), rend_tag{}); + } +}; + +} // namespace detail + +inline namespace niebloid { + +/// @addtogroup ranges +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::rend_niebloid rend{}; + +/// @} + +} // inline namespace niebloid + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_REND_HPP_ diff --git a/include/vccc/__ranges/size.hpp b/include/vccc/__ranges/size.hpp index 8c520b2d..a369b3d8 100644 --- a/include/vccc/__ranges/size.hpp +++ b/include/vccc/__ranges/size.hpp @@ -108,17 +108,17 @@ constexpr R size_impl(T&&, return_category<1, R>) { template constexpr R size_impl(T&& t, return_category<2, R>) { - return vccc_decay_copy(std::forward(t).size()); + return vccc_decay_copy(t.size()); } template constexpr R size_impl(T&& t, return_category<3, R>) { - return vccc_decay_copy(size(std::forward(t))); + return vccc_decay_copy(size(t)); } template constexpr R size_impl(T&& t, return_category<4, R>) { - return static_cast(ranges::end(std::forward(t)) - ranges::begin(std::forward(t))); + return static_cast(ranges::end(t) - ranges::begin(t)); } struct size_niebloid { diff --git a/include/vccc/__ranges/ssize.hpp b/include/vccc/__ranges/ssize.hpp index db885804..73150317 100644 --- a/include/vccc/__ranges/ssize.hpp +++ b/include/vccc/__ranges/ssize.hpp @@ -33,10 +33,10 @@ struct is_ranges_size_callable::value, int> = 0> constexpr auto operator()(T&& t) const { - using size_type = decltype(ranges::size(std::forward(t))); + using size_type = decltype(ranges::size(t)); using unsigned_type = std::make_unsigned_t; using R = typename ssize_type::type; - return static_cast(ranges::size(std::forward(t))); + return static_cast(ranges::size(t)); } }; diff --git a/include/vccc/__ranges/subrange.hpp b/include/vccc/__ranges/subrange.hpp index bc4cc4c1..b4c0e26e 100644 --- a/include/vccc/__ranges/subrange.hpp +++ b/include/vccc/__ranges/subrange.hpp @@ -356,6 +356,11 @@ template<> struct get_subrange<1> { } }; +template +struct is_subrange : std::false_type {}; +template +struct is_subrange> : std::true_type {}; + } // namespace detail template bases_; template using iterator_current = std::tuple< - iterator_t>, - iterator_t>... >; + iterator_t>, + iterator_t>... >; public: static_assert(input_range::value, "Constraints not satisfied"); @@ -184,7 +184,7 @@ class cartesian_product_view : public view_interface class iterator { - using Parent = detail::maybe_const; + using Parent = maybe_const; friend class cartesian_product_view; public: @@ -195,15 +195,15 @@ class cartesian_product_view : public view_interface::value, bidirectional_iterator_tag, std::conditional_t< - forward_range>::value, forward_iterator_tag, + forward_range>::value, forward_iterator_tag, input_iterator_tag >>>; using value_type = std::tuple< - range_value_t>, - range_value_t>... >; + range_value_t>, + range_value_t>... >; using reference = std::tuple< - range_reference_t>, - range_reference_t>... >; + range_reference_t>, + range_reference_t>... >; using difference_type = int; #if __cplusplus < 202002L using pointer = void; @@ -255,13 +255,13 @@ class cartesian_product_view : public view_interface>::value == false, int> = 0> + forward_range>::value == false, int> = 0> constexpr void operator++(int) { ++*this; } template>::value, int> = 0> + forward_range>::value, int> = 0> constexpr iterator operator++(int) { auto tmp = *this; ++*this; @@ -308,37 +308,37 @@ class cartesian_product_view : public view_interface>>::value, int> = 0> + equality_comparable>>::value, int> = 0> friend constexpr bool operator==(const iterator& x, const iterator& y) { return x.current_ == y.current_; } template>>::value, int> = 0> + equality_comparable>>::value, int> = 0> friend constexpr bool operator!=(const iterator& x, const iterator& y) { return !(x == y); } template>>::value, int> = 0> + equality_comparable>>::value, int> = 0> friend constexpr bool operator==(const iterator& x, default_sentinel_t) { return x.compare_with_default(); } template>>::value, int> = 0> + equality_comparable>>::value, int> = 0> friend constexpr bool operator!=(const iterator& x, default_sentinel_t) { return !x.compare_with_default(); } template>>::value, int> = 0> + equality_comparable>>::value, int> = 0> friend constexpr bool operator==(default_sentinel_t, const iterator& x) { return x.compare_with_default(); } template>>::value, int> = 0> + equality_comparable>>::value, int> = 0> friend constexpr bool operator!=(default_sentinel_t, const iterator& x) { return !x.compare_with_default(); } @@ -384,8 +384,8 @@ class cartesian_product_view : public view_interface >>, - // std::is_nothrow_move_constructible >>... + // std::is_nothrow_move_constructible >>, + // std::is_nothrow_move_constructible >>... // >::value // ) // { @@ -398,8 +398,8 @@ class cartesian_product_view : public view_interface> >, - indirectly_swappable< iterator_t> >... + indirectly_swappable< iterator_t> >, + indirectly_swappable< iterator_t> >... >::value ) { diff --git a/include/vccc/__ranges/views/common.hpp b/include/vccc/__ranges/views/common.hpp new file mode 100644 index 00000000..627d0bd4 --- /dev/null +++ b/include/vccc/__ranges/views/common.hpp @@ -0,0 +1,56 @@ +// +// Created by YongGyu Lee on 2/8/24. +// + +#ifndef VCCC_RANGES_VIEWS_COMMON_HPP +#define VCCC_RANGES_VIEWS_COMMON_HPP + +#include + +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__ranges/common_range.hpp" +#include "vccc/__ranges/range_adaptor_closure.hpp" +#include "vccc/__ranges/viewable_range.hpp" +#include "vccc/__ranges/views/all.hpp" +#include "vccc/__ranges/views/common_view.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/is_invocable.hpp" + +namespace vccc { +namespace ranges { +namespace views { +namespace detail { + +struct common_adaptor_object : range_adaptor_closure { + private: + template + constexpr auto call(R&& r, std::true_type /* all and common */) const { + return views::all(std::forward(r)); + } + template + constexpr auto call(R&& r, std::false_type /* all and common */) const { + return common_view>(std::forward(r)); + } + + public: + template::value, int> = 0> + constexpr auto operator()(R&& r) const { + return call(std::forward(r), conjunction, common_range>{}); + } +}; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +/// @brief [RangeAdaptorObject](https://en.cppreference.com/w/cpp/named_req/RangeAdaptorObject). +VCCC_INLINE_OR_STATIC constexpr detail::common_adaptor_object common{}; + +/// @} + +} // namespace views +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_COMMON_HPP diff --git a/include/vccc/__ranges/views/common_view.hpp b/include/vccc/__ranges/views/common_view.hpp new file mode 100644 index 00000000..e3009c63 --- /dev/null +++ b/include/vccc/__ranges/views/common_view.hpp @@ -0,0 +1,127 @@ +// +// Created by yonggyulee on 2/3/24. +// + +#ifndef VCCC_RANGES_VIEWS_COMMON_VIEW_HPP +#define VCCC_RANGES_VIEWS_COMMON_VIEW_HPP + +#include +#include + +#include "vccc/__concepts/copyable.hpp" +#include "vccc/__iterator/common_iterator.hpp" +#include "vccc/__ranges/borrowed_range.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/common_range.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__ranges/random_access_range.hpp" +#include "vccc/__ranges/size.hpp" +#include "vccc/__ranges/sized_range.hpp" +#include "vccc/__ranges/view_interface.hpp" +#include "vccc/__ranges/views/all.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/negation.hpp" + +namespace vccc { +namespace ranges { + +/// @addtogroup ranges +/// @{ + +/** +@brief Adapts a given \ref ranges::view "view" with different types for iterator/sentinel pair into a view that is also +a common_range. A common_view always has the same iterator/sentinel type + */ +template +class common_view : public view_interface> { + public: + static_assert(common_range::value == false, "Constraints not satisfied"); + static_assert(copyable>::value, "Constraints not satisfied"); + + common_view() = default; + + constexpr explicit common_view(V r) + : base_(std::move(r)) {} + + template::value, int> = 0> + constexpr V base() const& { + return base_; + } + + constexpr V base() && { + return std::move(base_); + } + + constexpr auto begin() { + return begin_impl(base_, conjunction, sized_range>{}); + } + + template::value, int> = 0> + constexpr auto begin() const { + return begin_impl(base_, conjunction, sized_range>{}); + } + + constexpr auto end() { + return end_impl(base_, conjunction, sized_range>{}); + } + + template::value, int> = 0> + constexpr auto end() const { + return end_impl(base_, conjunction, sized_range>{}); + } + + template::value, int> = 0> + constexpr auto size() { + return ranges::size(base_); + } + + template::value, int> = 0> + constexpr auto size() const { + return ranges::size(base_); + } + + private: + template + static constexpr auto begin_impl(Base&& base, std::true_type /* random_and_sized */) { + return ranges::begin(base); + } + template + static constexpr auto begin_impl(Base&& base, std::false_type /* random_and_sized */) { + return common_iterator, sentinel_t>(ranges::begin(base)); + } + + template + static constexpr auto end_impl(Base&& base, std::true_type /* random_and_sized */) { + return ranges::begin(base) + ranges::size(base); + } + template + static constexpr auto end_impl(Base&& base, std::false_type /* random_and_sized */) { + return common_iterator, sentinel_t>(ranges::end(base)); + } + + V base_{}; +}; + +#if __cplusplus >= 201703L + +template +common_view(R&&) -> common_view>; + +#endif + +template::value, int> = 0> +constexpr common_view> make_common_view(R&& r) { + return common_view>(std::forward(r)); +} + + +template +struct enable_borrowed_range> : enable_borrowed_range {}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_COMMON_VIEW_HPP diff --git a/include/vccc/__ranges/views/concat_view.hpp b/include/vccc/__ranges/views/concat_view.hpp new file mode 100644 index 00000000..8da57d18 --- /dev/null +++ b/include/vccc/__ranges/views/concat_view.hpp @@ -0,0 +1,494 @@ +// +// Created by YongGyu Lee on 2/13/24. +// + +#ifndef CONCAT_VIEW_HPP +#define CONCAT_VIEW_HPP + +#include +#include +#include +#include + +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__iterator/next.hpp" +#include "vccc/__ranges/common_range.hpp" +#include "vccc/__ranges/detail/simple_view.hpp" +#include "vccc/__ranges/distance.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/range_difference_t.hpp" +#include "vccc/__ranges/sized_range.hpp" +#include "vccc/__ranges/views/all.hpp" +#include "vccc/__tuple/tuple_fold.hpp" +#include "vccc/__tuple/tuple_transform.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/common_type.hpp" +#include "vccc/__type_traits/common_reference.hpp" +#include "vccc/__type_traits/has_typename_type.hpp" +#include "vccc/__type_traits/maybe_const.hpp" +#include "vccc/__utility/type_sequence.hpp" +#include "vccc/variant.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +template +using concat_compatible = conjunction< + has_typename_type...>>, + has_typename_type...>>, + has_typename_type...>> +>; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +// Modified from ranges-v3 library +template +struct concat_view : view_interface> { + static_assert(sizeof...(Rngs) != 0, "Constraints not satisfied"); + static_assert(conjunction...>::value, "Constraints not satisfied"); + static_assert(detail::concat_compatible::value, "Constraints not satisfied"); + + private: + using difference_type_ = common_type_t...>; + using BackBase = typename type_sequence::back; + + static constexpr std::size_t cranges = sizeof...(Rngs); + std::tuple bases_{}; + + public: + template + struct iterator; + + template + struct sentinel { + private: + friend struct sentinel; + friend struct iterator; + friend struct concat_view; + + using Parent = maybe_const; + using Base = maybe_const; + sentinel_t end_{}; + + constexpr sentinel(Parent& parent) + : end_(ranges::end(std::get(parent.bases_))) {} + + public: + sentinel() = default; + + template, + convertible_to, sentinel_t> + >::value, int> = 0> + constexpr sentinel(sentinel that) + : end_(std::move(that.end_)) {} + }; + + template + struct iterator { + using iterator_category = input_iterator_tag; + using iterator_concept = + std::conditional_t< + conjunction...>::value, random_access_iterator_tag, + std::conditional_t< + conjunction...>::value, bidirectional_iterator_tag, + std::conditional_t< + conjunction...>::value, forward_iterator_tag, + input_iterator_tag + >>>; + using value_type = common_type_t>...>; + using difference_type = common_type_t...>; + using reference = common_reference_t>...>; + using pointer = void; + + private: + friend struct iterator; + using Parent = maybe_const; + Parent* parent_; + variant>...> its_; + + template = 0> + void satisfy(std::integral_constant) { + if (std::get(its_) == ranges::end(std::get(parent_->bases_))) { + its_.template emplace(ranges::begin(std::get(parent_->bases_))); + this->satisfy(std::integral_constant{}); + } + } + + template= cranges - 1), int> = 0> + void satisfy(std::integral_constant) { /* no op */ } + + struct next_raw_visitor { + iterator* pos; + + template + void operator()(I& it, in_place_index_t) { + ++it; + pos->satisfy(std::integral_constant{}); + } + + template void operator()(U&, in_place_index_t) { /* no op */ } + }; + + struct prev_raw_visitor { + iterator* pos; + + template + void operator()(I& it, in_place_index_t<0>) { + --it; + } + + template, + bidirectional_iterator + >::value, int> = 0> + void operator()(I& it, in_place_index_t) { + if (it == ranges::begin(std::get(pos->parent_->bases_))) { + auto&& rng = std::get(pos->parent_->bases_); + + pos->its_.template emplace(ranges::next(ranges::begin(rng), ranges::end(rng))); + vccc::detail::variant_raw_visit(pos->its_.index(), pos->its_._base().storage(), *this); + } else { + --it; + } + } + + template void operator()(U&, in_place_index_t) { /* no op */ } + }; + + struct advance_fwd_raw_visitor { + iterator* pos; + difference_type n; + + template::value, int> = 0> + void operator()(I& it, in_place_index_t) { + ranges::advance(it, n); + } + + template::value, int> = 0> + void operator()(I& it, in_place_index_t) { + auto last = ranges::end(std::get(pos->parent_->bases_)); + // BUGBUG If distance(it, last) > n, then using bounded advance + // is O(n) when it need not be since the last iterator position + // is actually not interesting. Only the "rest" is needed, which + // can sometimes be O(1). + auto rest = ranges::advance(it, n, std::move(last)); + pos->satisfy(std::integral_constant{}); + if (rest != 0) { + vccc::detail::variant_raw_visit( + pos->its_.index(), pos->its_._base().storage(), advance_fwd_raw_visitor{pos, rest}); + } + } + + template void operator()(U&, in_place_index_t) { /* no op */ } + }; + + struct advance_rev_raw_visitor { + iterator* pos; + difference_type n; + + template::value, int> = 0> + void operator()(I& it, in_place_index_t<0>) { + ranges::advance(it, n); + } + + template::value, int> = 0> + void operator()(I& it, in_place_index_t) { + auto first = ranges::begin(std::get(pos->parent_->bases_)); + if (it == first) { + auto&& rng = std::get(pos->parent_->bases_); + pos->its_.template emplace(ranges::next(ranges::begin(rng), ranges::end(rng))); + vccc::detail::variant_raw_visit(pos->its_.index(), pos->its_._base().storage(), *this); + } else { + auto rest = ranges::advance(it, n, std::move(first)); + if (rest != 0) { + vccc::detail::variant_raw_visit( + pos->its_.index(), pos->its_._base().storage(), advance_rev_raw_visitor{pos, rest}); + } + } + } + + template void operator()(U&, in_place_index_t) { /* no op */ } + }; + + static difference_type distance_to_(std::integral_constant, iterator const &, iterator const &) { + // unreachable + return -1; + } + + template + static difference_type distance_to_(std::integral_constant, const iterator& from, const iterator& to) { + if (from.its_.index() > N) + return iterator::distance_to_(std::integral_constant{}, from, to); + + if (from.its_.index() == N) { + if (to.its_.index() == N) + return ranges::distance(vccc::detail::variant_raw_get(from.its_._base().storage(), in_place_index), + vccc::detail::variant_raw_get(to.its_._base().storage(), in_place_index)); + return ranges::distance(vccc::detail::variant_raw_get(from.its_._base().storage(), in_place_index), + ranges::end(std::get(from.parent_->bases_))) + + iterator::distance_to_(std::integral_constant{}, from, to); + } + + if (from.its_.index() < N && to.its_.index() > N) + return ranges::distance(std::get(from.parent_->bases_)) + + iterator::distance_to_(std::integral_constant{}, from, to); + + return ranges::distance(ranges::begin(std::get(from.parent_->bases_)), + vccc::detail::variant_raw_get(to.its_._base().storage(), in_place_index)); + } + + public: + iterator() = default; + + template + constexpr iterator(Parent* parent, in_place_index_t, It&& it) + : parent_(parent) + , its_{in_place_index, std::forward(it)} // ranges::begin(std::get<0>(parent->bases_)) + { + this->satisfy(std::integral_constant{}); + } + + // iterator(Parent* parent, end_tag) + // : parent_(parent) + // , its_{in_place_index, ranges::end(std::get(parent->bases_))} {} + + + template + >::value, int> = 0> + constexpr iterator(iterator that) + : parent_(that.parent_) + , its_(std::move(that.its_)) {} + + constexpr decltype(auto) operator*() const { + return its_.visit([](auto&& it) -> iterator::reference { return *it; }); + } + + template>...>, std::enable_if_t< + equality_comparable + ::value, int> = 0> + friend constexpr bool operator==(const iterator& x, const iterator& y) { + return x.its_ == y.its_; + } + + template>...>, std::enable_if_t< + equality_comparable + ::value, int> = 0> + friend constexpr bool operator!=(const iterator& x, const iterator& y) { + return !(x == y); + } + + friend constexpr bool operator==(const iterator& x, const sentinel& y) { + return x.equal(y); + } + + friend constexpr bool operator!=(const iterator& x, const sentinel& y) { + return !(x == y); + } + + friend constexpr bool operator==(const sentinel& y, const iterator& x) { + return x == y; + } + + friend constexpr bool operator!=(const sentinel& y, const iterator& x) { + return !(x == y); + } + + constexpr bool equal(const sentinel& pos) const { + return its_.index() == cranges - 1 && std::get(its_) == pos.end_; + } + + constexpr iterator& operator++() { + vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), next_raw_visitor{this}); + return *this; + } + + template, + negation>... + >::value, int> = 0> + constexpr void operator++(int) { + ++*this; + } + + template, + forward_range... + >::value, int> = 0> + constexpr iterator operator++(int) { + auto tmp = *this; + ++*this; + return tmp; + } + + template, + bidirectional_range... + >::value, int> = 0> + constexpr iterator& operator--() { + vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), prev_raw_visitor{this}); + return *this; + } + + template, + bidirectional_range... + >::value, int> = 0> + constexpr iterator& operator--(int) { + auto tmp = *this; + --*this; + return tmp; + } + + template, + random_access_range... + >::value, int> = 0> + constexpr iterator& operator+=(difference_type n) { + if (n > 0) { + vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), advance_fwd_raw_visitor{this, n}); + } else if (n < 0) { + vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), advance_rev_raw_visitor{this, n}); + } + return *this; + } + + template, + random_access_range... + >::value, int> = 0> + constexpr iterator& operator-=(difference_type n) { + *this += -n; + return *this; + } + + template, + sized_sentinel_for, iterator_t>... + >::value, int> = 0> + friend constexpr difference_type operator-(const iterator& x, const iterator& y) { + if (x.its_.index() <= y.its_.index()) + return -iterator::distance_to_(std::integral_constant{}, x, y); + return iterator::distance_to_(std::integral_constant{}, y, x); + } + + }; + + + concat_view() = default; + + explicit concat_view(Rngs... rngs) + : bases_{std::move(rngs)...} {} + + constexpr auto begin() { + using Const = conjunction...>; + return iterator{this, in_place_index<0>, ranges::begin(std::get<0>(bases_))}; + } + + template, + range... + >::value, int> = 0> + constexpr iterator begin() const { + return iterator{this, in_place_index<0>, ranges::begin(std::get<0>(bases_))}; + } + + template, + common_range... + >::value, int> = 0> + constexpr auto end() { + using Const = conjunction...>; + return iterator{this, in_place_index, ranges::end(std::get(bases_))}; + } + + template, + negation>... + >::value, int> = 0> + constexpr auto end() { + using Const = conjunction...>; + return sentinel{*this}; + } + + template, + range... + >::value, int> = 0> + constexpr auto end() const { + return end_impl(conjunction...>{}); + } + + template, + sized_range... + >::value, int> = 0> + constexpr auto size() { + return vccc::tuple_fold_left( + vccc::tuple_transform(bases_, [](auto&& r) { return r.size(); }), + std::size_t{0}, + std::plus<>{} + ); + } + + template, + sized_range... + >::value, int> = 0> + constexpr auto size() const { + return vccc::tuple_fold_left( + vccc::tuple_transform(bases_, [](auto&& r) { return r.size(); }), + std::size_t{0}, + std::plus<>{} + ); + } + + private: + constexpr iterator end_impl(std::true_type /* common_range */) const { + return iterator{this, in_place_index, ranges::end(std::get(bases_))}; + } + + constexpr sentinel end_impl(std::false_type /* common_range */) const { + return sentinel{*this}; + } +}; + +#if __cplusplus >= 201703L + +template +concat_view(Rng &&...) // + -> concat_view...>; + +#endif + +namespace views { +namespace detail { + +struct concat_niebloid { + template..., + input_range... + >::value, int> = 0> + constexpr auto operator()(R&&... rs) const { + return concat_view...>{views::all(std::forward(rs))...}; + } +}; + +} // namespace detail + +/// @brief concatenate ranges +constexpr VCCC_INLINE_OR_STATIC detail::concat_niebloid concat{}; + +/// @} + +} // namespace views + +} // namespace ranges +} // namespace vccc + +#endif //CONCAT_VIEW_HPP diff --git a/include/vccc/__ranges/views/concat_with_view.hpp b/include/vccc/__ranges/views/concat_with_view.hpp new file mode 100644 index 00000000..72e9afb8 --- /dev/null +++ b/include/vccc/__ranges/views/concat_with_view.hpp @@ -0,0 +1,495 @@ +// +// Created by YongGyu Lee on 2/20/24. +// + +#ifndef CONCAT_WITH_VIEW_HPP +#define CONCAT_WITH_VIEW_HPP + +#include +#include +#include +#include + +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__iterator/next.hpp" +#include "vccc/__ranges/common_range.hpp" +#include "vccc/__ranges/detail/simple_view.hpp" +#include "vccc/__ranges/distance.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/range_difference_t.hpp" +#include "vccc/__ranges/sized_range.hpp" +#include "vccc/__ranges/views/all.hpp" +#include "vccc/__ranges/views/maybe_const.hpp" +#include "vccc/__tuple/tuple_fold.hpp" +#include "vccc/__tuple/tuple_transform.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/common_type.hpp" +#include "vccc/__type_traits/common_reference.hpp" +#include "vccc/__type_traits/has_typename_type.hpp" +#include "vccc/__utility/type_sequence.hpp" +#include "vccc/variant.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +template +using concat_with_compatible = conjunction< + has_typename_type, range_value_t...>>, + has_typename_type, range_reference_t...>>, + has_typename_type, range_rvalue_reference_t...>> +>; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +template +struct concat_with_view : view_interface> { + static_assert(sizeof...(Rngs) != 0, "Constraints not satisfied"); + static_assert(conjunction...>::value, "Constraints not satisfied"); + static_assert(view::value, "Constraints not satisfied"); + static_assert(detail::concat_with_compatible::value, "Constraints not satisfied"); + + private: + using difference_type_ = common_type_t...>; + using BackBase = typename type_sequence::back; + + static constexpr std::size_t cranges = sizeof...(Rngs); + std::tuple bases_{}; + Pattern pattern_; + + public: + template + struct iterator; + + template + struct sentinel { + private: + friend struct sentinel; + friend struct iterator; + friend class concat_with_view; + + using Parent = maybe_const; + using Base = maybe_const; + sentinel_t end_{}; + + constexpr sentinel(Parent& parent) + : end_(ranges::end(std::get(parent.bases_))) {} + + public: + sentinel() = default; + + template, + convertible_to, sentinel_t> + >::value, int> = 0> + constexpr sentinel(sentinel that) + : end_(std::move(that.end_)) {} + }; + + template + struct iterator { + using iterator_category = input_iterator_tag; + using iterator_concept = + std::conditional_t< + conjunction...>::value, random_access_iterator_tag, + std::conditional_t< + conjunction...>::value, bidirectional_iterator_tag, + std::conditional_t< + conjunction...>::value, forward_iterator_tag, + input_iterator_tag + >>>; + using value_type = common_type_t>...>; + using difference_type = common_type_t...>; + using reference = common_reference_t>...>; + using pointer = void; + + private: + friend struct iterator; + using Parent = maybe_const; + Parent* parent_; + variant>...> its_; + + template = 0> + void satisfy(std::integral_constant) { + if (std::get(its_) == ranges::end(std::get(parent_->bases_))) { + its_.template emplace(ranges::begin(std::get(parent_->bases_))); + this->satisfy(std::integral_constant{}); + } + } + + template= cranges - 1), int> = 0> + void satisfy(std::integral_constant) { /* no op */ } + + struct next_raw_visitor { + iterator* pos; + + template + void operator()(I& it, in_place_index_t) { + ++it; + pos->satisfy(std::integral_constant{}); + } + + template void operator()(U&, in_place_index_t) { /* no op */ } + }; + + struct prev_raw_visitor { + iterator* pos; + + template + void operator()(I& it, in_place_index_t<0>) { + --it; + } + + template, + bidirectional_iterator + >::value, int> = 0> + void operator()(I& it, in_place_index_t) { + if (it == ranges::begin(std::get(pos->parent_->bases_))) { + auto&& rng = std::get(pos->parent_->bases_); + + pos->its_.template emplace(ranges::next(ranges::begin(rng), ranges::end(rng))); + vccc::detail::variant_raw_visit(pos->its_.index(), pos->its_._base().storage(), *this); + } else { + --it; + } + } + + template void operator()(U&, in_place_index_t) { /* no op */ } + }; + + struct advance_fwd_raw_visitor { + iterator* pos; + difference_type n; + + template::value, int> = 0> + void operator()(I& it, in_place_index_t) { + ranges::advance(it, n); + } + + template::value, int> = 0> + void operator()(I& it, in_place_index_t) { + auto last = ranges::end(std::get(pos->parent_->bases_)); + // BUGBUG If distance(it, last) > n, then using bounded advance + // is O(n) when it need not be since the last iterator position + // is actually not interesting. Only the "rest" is needed, which + // can sometimes be O(1). + auto rest = ranges::advance(it, n, std::move(last)); + pos->satisfy(std::integral_constant{}); + if (rest != 0) { + vccc::detail::variant_raw_visit( + pos->its_.index(), pos->its_._base().storage(), advance_fwd_raw_visitor{pos, rest}); + } + } + + template void operator()(U&, in_place_index_t) { /* no op */ } + }; + + struct advance_rev_raw_visitor { + iterator* pos; + difference_type n; + + template::value, int> = 0> + void operator()(I& it, in_place_index_t<0>) { + ranges::advance(it, n); + } + + template::value, int> = 0> + void operator()(I& it, in_place_index_t) { + auto first = ranges::begin(std::get(pos->parent_->bases_)); + if (it == first) { + auto&& rng = std::get(pos->parent_->bases_); + pos->its_.template emplace(ranges::next(ranges::begin(rng), ranges::end(rng))); + vccc::detail::variant_raw_visit(pos->its_.index(), pos->its_._base().storage(), *this); + } else { + auto rest = ranges::advance(it, n, std::move(first)); + if (rest != 0) { + vccc::detail::variant_raw_visit( + pos->its_.index(), pos->its_._base().storage(), advance_rev_raw_visitor{pos, rest}); + } + } + } + + template void operator()(U&, in_place_index_t) { /* no op */ } + }; + + static difference_type distance_to_(std::integral_constant, iterator const &, iterator const &) { + // unreachable + return -1; + } + + template + static difference_type distance_to_(std::integral_constant, const iterator& from, const iterator& to) { + if (from.its_.index() > N) + return iterator::distance_to_(std::integral_constant{}, from, to); + + if (from.its_.index() == N) { + if (to.its_.index() == N) + return ranges::distance(vccc::detail::variant_raw_get(from.its_._base().storage(), in_place_index), + vccc::detail::variant_raw_get(to.its_._base().storage(), in_place_index)); + return ranges::distance(vccc::detail::variant_raw_get(from.its_._base().storage(), in_place_index), + ranges::end(std::get(from.parent_->bases_))) + + iterator::distance_to_(std::integral_constant{}, from, to); + } + + if (from.its_.index() < N && to.its_.index() > N) + return ranges::distance(std::get(from.parent_->bases_)) + + iterator::distance_to_(std::integral_constant{}, from, to); + + return ranges::distance(ranges::begin(std::get(from.parent_->bases_)), + vccc::detail::variant_raw_get(to.its_._base().storage(), in_place_index)); + } + + public: + iterator() = default; + + template + constexpr iterator(Parent* parent, in_place_index_t, It&& it) + : parent_(parent) + , its_{in_place_index, std::forward(it)} // ranges::begin(std::get<0>(parent->bases_)) + { + this->satisfy(std::integral_constant{}); + } + + // iterator(Parent* parent, end_tag) + // : parent_(parent) + // , its_{in_place_index, ranges::end(std::get(parent->bases_))} {} + + + template + >::value, int> = 0> + constexpr iterator(iterator that) + : parent_(that.parent_) + , its_(std::move(that.its_)) {} + + constexpr decltype(auto) operator*() const { + return its_.visit([](auto&& it) -> iterator::reference { return *it; }); + } + + template>...>, std::enable_if_t< + equality_comparable + ::value, int> = 0> + friend constexpr bool operator==(const iterator& x, const iterator& y) { + return x.its_ == y.its_; + } + + template>...>, std::enable_if_t< + equality_comparable + ::value, int> = 0> + friend constexpr bool operator!=(const iterator& x, const iterator& y) { + return !(x == y); + } + + friend constexpr bool operator==(const iterator& x, const sentinel& y) { + return x.equal(y); + } + + friend constexpr bool operator!=(const iterator& x, const sentinel& y) { + return !(x == y); + } + + friend constexpr bool operator==(const sentinel& y, const iterator& x) { + return x == y; + } + + friend constexpr bool operator!=(const sentinel& y, const iterator& x) { + return !(x == y); + } + + constexpr bool equal(const sentinel& pos) const { + return its_.index() == cranges - 1 && std::get(its_) == pos.end_; + } + + constexpr iterator& operator++() { + vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), next_raw_visitor{this}); + return *this; + } + + template, + negation>... + >::value, int> = 0> + constexpr void operator++(int) { + ++*this; + } + + template, + forward_range... + >::value, int> = 0> + constexpr iterator operator++(int) { + auto tmp = *this; + ++*this; + return tmp; + } + + template, + bidirectional_range... + >::value, int> = 0> + constexpr iterator& operator--() { + vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), prev_raw_visitor{this}); + return *this; + } + + template, + bidirectional_range... + >::value, int> = 0> + constexpr iterator& operator--(int) { + auto tmp = *this; + --*this; + return tmp; + } + + template, + random_access_range... + >::value, int> = 0> + constexpr iterator& operator+=(difference_type n) { + if (n > 0) { + vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), advance_fwd_raw_visitor{this, n}); + } else if (n < 0) { + vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), advance_rev_raw_visitor{this, n}); + } + return *this; + } + + template, + random_access_range... + >::value, int> = 0> + constexpr iterator& operator-=(difference_type n) { + *this += -n; + return *this; + } + + template, + sized_sentinel_for, iterator_t>... + >::value, int> = 0> + friend constexpr difference_type operator-(const iterator& x, const iterator& y) { + if (x.its_.index() <= y.its_.index()) + return -iterator::distance_to_(std::integral_constant{}, x, y); + return iterator::distance_to_(std::integral_constant{}, y, x); + } + + }; + + + concat_with_view() = default; + + explicit concat_with_view(Rngs... rngs) + : bases_{std::move(rngs)...} {} + + constexpr auto begin() { + using Const = conjunction...>; + return iterator{this, in_place_index<0>, ranges::begin(std::get<0>(bases_))}; + } + + template, + range... + >::value, int> = 0> + constexpr iterator begin() const { + return iterator{this, in_place_index<0>, ranges::begin(std::get<0>(bases_))}; + } + + template, + common_range... + >::value, int> = 0> + constexpr auto end() { + using Const = conjunction...>; + return iterator{this, in_place_index, ranges::end(std::get(bases_))}; + } + + template, + negation>... + >::value, int> = 0> + constexpr auto end() { + using Const = conjunction...>; + return sentinel{*this}; + } + + template, + range... + >::value, int> = 0> + constexpr auto end() const { + return end_impl(conjunction...>{}); + } + + template, + sized_range... + >::value, int> = 0> + constexpr auto size() { + return vccc::tuple_fold_left( + vccc::tuple_transform(bases_, [](auto&& r) { return r.size(); }), + std::size_t{0}, + std::plus<>{} + ); + } + + template, + sized_range... + >::value, int> = 0> + constexpr auto size() const { + return vccc::tuple_fold_left( + vccc::tuple_transform(bases_, [](auto&& r) { return r.size(); }), + std::size_t{0}, + std::plus<>{} + ); + } + + private: + constexpr iterator end_impl(std::true_type /* common_range */) const { + return iterator{this, in_place_index, ranges::end(std::get(bases_))}; + } + + constexpr sentinel end_impl(std::false_type /* common_range */) const { + return sentinel{*this}; + } +}; + +#if __cplusplus >= 201703L + +template +concat_view(Rng &&...) // + -> concat_view...>; + +#endif + +namespace views { +namespace detail { + +struct concat_with_niebloid { + template..., + input_range... + >::value, int> = 0> + constexpr auto operator()(R&&... rs) const { + return concat_with_view...>{views::all(std::forward(rs))...}; + } +}; + +} // namespace detail + +/// @brief concatenate ranges +constexpr VCCC_INLINE_OR_STATIC detail::concat_with_niebloid concat_with{}; + +/// @} + +} // namespace views + +} // namespace ranges +} // namespace vccc + +#endif // CONCAT_WITH_VIEW_HPP diff --git a/include/vccc/__ranges/views/drop.hpp b/include/vccc/__ranges/views/drop.hpp index 6c2ca4eb..7bd7b826 100644 --- a/include/vccc/__ranges/views/drop.hpp +++ b/include/vccc/__ranges/views/drop.hpp @@ -68,12 +68,7 @@ struct drop_niebloid { } // subrange - 2 / 3 - template - struct is_subrange : std::false_type {}; - template - struct is_subrange> : std::true_type {}; - - template, random_access_range, sized_range>::value /* true */> + template, random_access_range, sized_range>::value /* true */> struct return_category_subrange : std::true_type { using category = std::conditional_t::value, return_category<2, subrange, sentinel_t, subrange_kind::sized> >, @@ -89,8 +84,8 @@ struct drop_niebloid { constexpr U operator()(R&& e, D f, return_category<2, U>) const { auto inc = (std::min)(ranges::distance(e), f); return U( - ranges::begin(std::forward(e)) + inc, - ranges::end(std::forward(e)), + ranges::begin(e) + inc, + ranges::end(e), static_cast>(ranges::distance(e) - inc) ); } @@ -133,8 +128,8 @@ struct drop_niebloid { template constexpr U operator()(R&& e, D f, return_category<3, U>) const { return U( - ranges::begin(std::forward(e)) + (std::min)(ranges::distance(std::forward(e)), f), - ranges::end(std::forward(e)) + ranges::begin(e) + (std::min)(ranges::distance(e), f), + ranges::end(e) ); } diff --git a/include/vccc/__ranges/views/drop_while.hpp b/include/vccc/__ranges/views/drop_while.hpp new file mode 100644 index 00000000..e573e2eb --- /dev/null +++ b/include/vccc/__ranges/views/drop_while.hpp @@ -0,0 +1,63 @@ +// +// Created by yonggyulee on 2024/02/20. +// + +#ifndef VCCC_RANGES_VIEWS_DROP_WHILE_HPP +#define VCCC_RANGES_VIEWS_DROP_WHILE_HPP + +#include +#include +#include +#include + +#include "vccc/__ranges/viewable_range.hpp" +#include "vccc/__ranges/views/all.hpp" +#include "vccc/__ranges/views/drop_while_view.hpp" +#include "vccc/__type_traits/remove_cvref.hpp" + +namespace vccc { +namespace ranges { +namespace views { +namespace detail { + +template +class drop_while_adaptor_closure : public range_adaptor_closure> { + public: + explicit drop_while_adaptor_closure(F func) : func_(func) {} + + template::value, int> = 0> + constexpr drop_while_view, F> + operator()(R&& r) const { + return drop_while_view, F>(std::forward(r), *func_); + } + + private: + movable_box func_; +}; + +struct drop_while_niebloid { + template::value, int> = 0> + constexpr auto operator()(R&& r, Pred&& pred) const { + return drop_while_view, std::decay_t>(std::forward(r), std::forward(pred)); + } + + template>::value, int> = 0> + constexpr auto operator()(Pred&& pred) const { + return drop_while_adaptor_closure>(std::forward(pred)); + } +}; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::drop_while_niebloid drop_while{}; + +/// @} + +} // namespace views +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_DROP_WHILE_HPP diff --git a/include/vccc/__ranges/views/drop_while_view.hpp b/include/vccc/__ranges/views/drop_while_view.hpp new file mode 100644 index 00000000..791711ed --- /dev/null +++ b/include/vccc/__ranges/views/drop_while_view.hpp @@ -0,0 +1,99 @@ +// +// Created by YongGyu Lee on 2/13/24. +// + +#ifndef VCCC_RANGES_VIEWS_DROP_WHILE_VIEW_HPP_ +#define VCCC_RANGES_VIEWS_DROP_WHILE_VIEW_HPP_ + +#include +#include + +#include "vccc/__algorithm/ranges/find_if_not.hpp" +#include "vccc/__concepts/copy_constructible.hpp" +#include "vccc/__iterator/indirect_unary_predicate.hpp" +#include "vccc/__ranges/enable_borrowed_range.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/input_range.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__ranges/movable_box.hpp" +#include "vccc/__ranges/non_propagating_cache.hpp" +#include "vccc/__ranges/view.hpp" +#include "vccc/__ranges/view_interface.hpp" +#include "vccc/__ranges/views/all.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/has_typename_type.hpp" + +namespace vccc { +namespace ranges { + +/// @addtogroup ranges +/// @{ + +template +class drop_while_view : public view_interface> { + public: + static_assert(view::value, "Constraints not satisfied"); + static_assert(input_range::value, "Constraints not satisfied"); + static_assert(std::is_object::value, "Constraints not satisfied"); + static_assert(indirect_unary_predicate>::value, "Constraints not satisfied"); + + drop_while_view() = default; + + constexpr explicit drop_while_view(V base, Pred pred) + : base_(std::move(base)), pred_(std::move(pred)) {} + + template::value, int> = 0> + constexpr V base() const& { + return base_; + } + + constexpr V base() && { + return std::move(base_); + } + + constexpr const Pred& pred() const { + return *pred_; + } + + constexpr auto begin() { + if (!cached_begin_) { + cached_begin_.emplace(ranges::find_if_not(base_, std::cref(*pred_))); + } + return *cached_begin_; + } + + constexpr auto end() { + return ranges::end(base_); + } + + private: + V base_{}; + movable_box pred_{}; + using begin_type = decltype(ranges::find_if_not(base_, std::cref(*pred_))); + non_propagating_cache cached_begin_; +}; + +#if __cplusplus >= 201703L + +template +drop_while_view(R&&, Pred) -> drop_while_view, Pred>; + +#endif + +template>, + std::is_object +>::value, int> = 0> +constexpr auto make_drop_while_view(R&& r, Pred&& pred) { + return drop_while_view, std::decay_t>(std::forward(r), std::forward(pred)); +} + +template +struct enable_borrowed_range> : enable_borrowed_range {}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_DROP_WHILE_VIEW_HPP_ diff --git a/include/vccc/__ranges/views/elements_view.hpp b/include/vccc/__ranges/views/elements_view.hpp index 997e862e..b8f3eb3a 100644 --- a/include/vccc/__ranges/views/elements_view.hpp +++ b/include/vccc/__ranges/views/elements_view.hpp @@ -31,13 +31,13 @@ #include "vccc/__ranges/view.hpp" #include "vccc/__ranges/view_interface.hpp" #include "vccc/__ranges/viewable_range.hpp" -#include "vccc/__ranges/views/maybe_const.hpp" #include "vccc/__tuple/tuple_like.hpp" #include "vccc/__type_traits/bool_constant.hpp" #include "vccc/__type_traits/conjunction.hpp" #include "vccc/__type_traits/disjunction.hpp" #include "vccc/__type_traits/has_typename_type.hpp" #include "vccc/__type_traits/is_invocable.hpp" +#include "vccc/__type_traits/maybe_const.hpp" #include "vccc/__type_traits/negation.hpp" #include "vccc/__type_traits/remove_cvref.hpp" #include "vccc/__utility/cxx20_rel_ops.hpp" @@ -289,7 +289,7 @@ class elements_view : public view_interface> { template, - iterator_t> + iterator_t> >::value, int> = 0> friend constexpr bool operator==(const iterator& x, const sentinel& y) { using namespace vccc::rel_ops; @@ -299,7 +299,7 @@ class elements_view : public view_interface> { template, - iterator_t> + iterator_t> >::value, int> = 0> friend constexpr bool operator!=(const iterator& x, const sentinel& y) { return !(x == y); @@ -308,7 +308,7 @@ class elements_view : public view_interface> { template, - iterator_t> + iterator_t> >::value, int> = 0> friend constexpr bool operator==(const sentinel& y, const iterator& x) { return x == y; @@ -317,7 +317,7 @@ class elements_view : public view_interface> { template, - iterator_t> + iterator_t> >::value, int> = 0> friend constexpr bool operator!=(const sentinel& y, const iterator& x) { return !(x == y); @@ -326,9 +326,9 @@ class elements_view : public view_interface> { template, - iterator_t> + iterator_t> >::value, int> = 0> - friend constexpr range_difference_t> + friend constexpr range_difference_t> operator-(const iterator& x, const sentinel& y) { return x.base() - y.end_; } @@ -336,9 +336,9 @@ class elements_view : public view_interface> { template, - iterator_t> + iterator_t> >::value, int> = 0> - friend constexpr range_difference_t> + friend constexpr range_difference_t> operator-(const sentinel& y, const iterator& x) { return y.end_ - x.base(); } diff --git a/include/vccc/__ranges/views/enumerate.hpp b/include/vccc/__ranges/views/enumerate.hpp index d6ad4433..228f74cd 100644 --- a/include/vccc/__ranges/views/enumerate.hpp +++ b/include/vccc/__ranges/views/enumerate.hpp @@ -6,6 +6,8 @@ #define VCCC_RANGES_VIEWS_ENUMERATE_HPP #include +#include +#include #include "vccc/__core/inline_or_static.hpp" #include "vccc/__ranges/range_adaptor_closure.hpp" @@ -18,13 +20,14 @@ namespace ranges { namespace views { namespace detail { -class enumerate_adaptor_closure : public range_adaptor_closure { - public: +template class Tuple> +class enumerate_adaptor_closure : public range_adaptor_closure> { + public: enumerate_adaptor_closure() = default; template::value, int> = 0> constexpr auto operator()(R&& r) const { - return enumerate_view>(std::forward(r)); + return enumerate_view, Tuple>(std::forward(r)); } }; @@ -33,7 +36,10 @@ class enumerate_adaptor_closure : public range_adaptor_closure enumerate{}; + +/// @brief return std::pair instead of std::tuple +VCCC_INLINE_OR_STATIC constexpr detail::enumerate_adaptor_closure enumerate_pair{}; /// @} diff --git a/include/vccc/__ranges/views/enumerate_view.hpp b/include/vccc/__ranges/views/enumerate_view.hpp index c86fc0c9..77118fe4 100644 --- a/include/vccc/__ranges/views/enumerate_view.hpp +++ b/include/vccc/__ranges/views/enumerate_view.hpp @@ -33,12 +33,12 @@ #include "vccc/__ranges/sized_range.hpp" #include "vccc/__ranges/view.hpp" #include "vccc/__ranges/view_interface.hpp" -#include "vccc/__ranges/views/maybe_const.hpp" #if __cplusplus >= 201703L #include "vccc/__ranges/views/all.hpp" #endif #include "vccc/__type_traits/bool_constant.hpp" #include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/maybe_const.hpp" #include "vccc/__utility/cxx20_rel_ops.hpp" namespace vccc { @@ -59,7 +59,7 @@ struct range_with_movable_reference /// @addtogroup ranges /// @{ -template +template class Tuple = std::tuple> class enumerate_view : public view_interface> { public: static_assert(view::value, "Constraints not satisfied"); @@ -74,7 +74,7 @@ class enumerate_view : public view_interface> { template friend class sentinel; - using Base = detail::maybe_const; + using Base = maybe_const; public: using iterator_category = input_iterator_tag; @@ -88,10 +88,10 @@ class enumerate_view : public view_interface> { input_iterator_tag >>>; using difference_type = range_difference_t; - using value_type = std::tuple>; - private: - using reference_type = std::tuple>; - public: + using value_type = Tuple>; + using pointer = void; + using reference = Tuple>; + iterator() = default; template> { } constexpr auto operator*() const { - return reference_type(pos_, *current_); + return reference(pos_, *current_); } template::value, int> = 0> constexpr auto operator[](difference_type n) const { - return reference_type(pos_ + n, current_[n]); + return reference(pos_ + n, current_[n]); } constexpr iterator& operator++() { @@ -279,10 +279,10 @@ class enumerate_view : public view_interface> { template, - iterator_t> + iterator_t> > >::value, int> = 0> - friend constexpr range_difference_t> + friend constexpr range_difference_t> operator-(const iterator& x, const sentinel& y) { return x.base() - y.base(); } @@ -290,10 +290,10 @@ class enumerate_view : public view_interface> { template, - iterator_t> + iterator_t> > >::value, int> = 0> - friend constexpr range_difference_t> + friend constexpr range_difference_t> operator-(const sentinel& y, const iterator& x) { return y.base() - x.base(); } diff --git a/include/vccc/__ranges/views/join_view.hpp b/include/vccc/__ranges/views/join_view.hpp index 23e5c592..014bf0fb 100644 --- a/include/vccc/__ranges/views/join_view.hpp +++ b/include/vccc/__ranges/views/join_view.hpp @@ -27,10 +27,10 @@ #include "vccc/__ranges/view.hpp" #include "vccc/__ranges/view_interface.hpp" #include "vccc/__ranges/views/all.hpp" -#include "vccc/__ranges/views/maybe_const.hpp" #include "vccc/__type_traits/conjunction.hpp" #include "vccc/__type_traits/common_type.hpp" #include "vccc/__type_traits/has_operator_arrow.hpp" +#include "vccc/__type_traits/maybe_const.hpp" #include "vccc/__utility/as_const.hpp" #include "vccc/__utility/cxx20_rel_ops.hpp" @@ -105,7 +105,7 @@ class join_view : public view_interface> { private: template - using InnerRng = range_reference_t>; + using InnerRng = range_reference_t>; public: template class iterator; @@ -113,9 +113,9 @@ class join_view : public view_interface> { template class sentinel; template - class iterator : detail::join_view_iterator_category> { - using Parent = detail::maybe_const; - using Base = detail::maybe_const; + class iterator : detail::join_view_iterator_category> { + using Parent = maybe_const; + using Base = maybe_const; using OuterIter = iterator_t; using InnerIter = iterator_t>; static constexpr bool ref_is_glvalue = std::is_reference>::value; @@ -321,8 +321,8 @@ class join_view : public view_interface> { template class sentinel { - using Parent = detail::maybe_const; - using Base = detail::maybe_const; + using Parent = maybe_const; + using Base = maybe_const; public: sentinel() = default; diff --git a/include/vccc/__ranges/views/join_with.hpp b/include/vccc/__ranges/views/join_with.hpp new file mode 100644 index 00000000..b3801f05 --- /dev/null +++ b/include/vccc/__ranges/views/join_with.hpp @@ -0,0 +1,83 @@ +// +// Created by yonggyulee on 2/13/24. +// + +#ifndef VCCC_RANGES_VIEWS_JOIN_WITH_HPP_ +#define VCCC_RANGES_VIEWS_JOIN_WITH_HPP_ + +#include +#include + +#include "vccc/__concepts/different_from.hpp" +#include "vccc/__ranges/range.hpp" +#include "vccc/__ranges/range_adaptor_closure.hpp" +#include "vccc/__ranges/range_reference_t.hpp" +#include "vccc/__ranges/range_value_t.hpp" +#include "vccc/__ranges/viewable_range.hpp" +#include "vccc/__ranges/views/all.hpp" +#include "vccc/__ranges/views/join_with_view.hpp" +#include "vccc/__ranges/views/single.hpp" + +namespace vccc { +namespace ranges { +namespace views { +namespace detail { + +template +class join_with_adaptor_object : public range_adaptor_closure> { + public: + template::value, int> = 0> + constexpr explicit join_with_adaptor_object(U&& pattern) + : pattern_(std::forward(pattern)) {} + + template::value, int> = 0> + constexpr auto operator()(R&& r) const& { + return join_with_view, all_t>{std::forward(r), pattern_}; + } + + template::value, int> = 0> + constexpr auto operator()(R&& r) && { + return join_with_view, all_t>{std::forward(r), std::move(pattern_)}; + } + + private: + Pattern pattern_; +}; + +struct join_with_niebloid { + template, + different_from>> + >::value, int> = 0> + constexpr auto operator()(R&& r, Pattern&& pattern) const { + return join_with_view, all_t>{std::forward(r), std::forward(pattern)}; + } + + template + >::value, int> = 0> + constexpr auto operator()(R&& r, range_value_t> pattern) const { + return join_with_view, single_view>>>{ + std::forward(r), std::move(pattern)}; + } + + template + constexpr auto operator()(Pattern&& pattern) const { + return join_with_adaptor_object>{std::forward(pattern)}; + } +}; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::join_with_niebloid join_with{}; + +/// @} + +} // namespace views +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_JOIN_WITH_HPP_ diff --git a/include/vccc/__ranges/views/join_with_view.hpp b/include/vccc/__ranges/views/join_with_view.hpp new file mode 100644 index 00000000..9639f34a --- /dev/null +++ b/include/vccc/__ranges/views/join_with_view.hpp @@ -0,0 +1,601 @@ +// +// Created by yonggyulee on 2/13/24. +// + +#ifndef VCCC_RANGES_VIEWS_JOIN_WITH_VIEW_HPP_ +#define VCCC_RANGES_VIEWS_JOIN_WITH_VIEW_HPP_ + +#include +#include + +#include "vccc/__concepts/common_reference_with.hpp" +#include "vccc/__concepts/common_with.hpp" +#include "vccc/__concepts/convertible_to.hpp" +#include "vccc/__concepts/derived_from.hpp" +#include "vccc/__concepts/equality_comparable.hpp" +#include "vccc/__iterator/iterator_tag.hpp" +#include "vccc/__iterator/iterator_traits/cxx20_iterator_traits.hpp" +#include "vccc/__memory/addressof.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/bidirectional_range.hpp" +#include "vccc/__ranges/common_range.hpp" +#include "vccc/__ranges/detail/simple_view.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/forward_range.hpp" +#include "vccc/__ranges/input_range.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__ranges/non_propagating_cache.hpp" +#include "vccc/__ranges/range_difference_t.hpp" +#include "vccc/__ranges/range_reference_t.hpp" +#include "vccc/__ranges/range_value_t.hpp" +#include "vccc/__ranges/sentinel_t.hpp" +#include "vccc/__ranges/view.hpp" +#include "vccc/__ranges/view_interface.hpp" +#include "vccc/__ranges/views/all.hpp" +#include "vccc/__ranges/views/single.hpp" +#include "vccc/__type_traits/common_reference.hpp" +#include "vccc/__type_traits/common_type.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/maybe_const.hpp" +#include "vccc/__type_traits/negation.hpp" +#include "vccc/__utility/cxx20_rel_ops.hpp" +#include "vccc/variant.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +template +using join_with_compatible = conjunction< + common_with, range_value_t>, + common_reference_with, range_reference_t>, + common_reference_with, range_rvalue_reference_t> + >; + +template::value /* true */> +class join_with_view_base : public view_interface { + struct cache_wrapper { + template + constexpr cache_wrapper(const I& i) noexcept( + std::is_nothrow_constructible, decltype(*i)>::value) + : val(*i) {} + + std::remove_cv_t> val; + }; + protected: + non_propagating_cache inner_base_{}; +}; + +template +class join_with_view_base : public view_interface { + protected: + non_propagating_cache>> inner_base_{}; + non_propagating_cache> outer_it_{}; +}; + + +template +using join_with_view_iterator_concept = + std::conditional_t< + conjunction< + std::is_reference>, + bidirectional_range, + bidirectional_range, + bidirectional_range, + common_range, + common_range + >::value, bidirectional_iterator_tag, + std::conditional_t< + conjunction< + std::is_reference>, + forward_range, + forward_range + >::value, forward_iterator_tag, + input_iterator_tag + >>; + +template>::iterator_category, + typename InnerC = typename cxx20_iterator_traits>::iterator_category, + typename PatternC = typename cxx20_iterator_traits>::iterator_category, + typename IterConcept = join_with_view_iterator_concept> +struct join_with_view_iterator_category { + using iterator_concept = IterConcept; +#if __cplusplus < 202002L + using iterator_category = iterator_ignore; +#endif +}; + +template +struct join_with_view_iterator_category { + using iterator_concept = forward_iterator_tag; + using iterator_category = + std::conditional_t< + negation, range_reference_t> + >>::value, + input_iterator_tag, + std::conditional_t< + conjunction< + derived_from, + derived_from, + derived_from + >::value, + bidirectional_iterator_tag, + std::conditional_t< + conjunction< + derived_from, + derived_from, + derived_from + >::value, + forward_iterator_tag, + input_iterator_tag + >>>; +}; + +template::value/* false */> +class join_with_view_iterator_base : public join_with_view_iterator_category {}; + +template +class join_with_view_iterator_base + : public join_with_view_iterator_category +{ + protected: + join_with_view_iterator_base() = default; + + constexpr explicit join_with_view_iterator_base(iterator_t&& outer_it) + : outer_it_(std::move(outer_it)) {} + + iterator_t outer_it_{}; +}; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +// Implementation taken from MSVC +template +class join_with_view : public detail::join_with_view_base> { + public: + static_assert(input_range::value, "Constraints not satisfied"); + static_assert(forward_range::value, "Constraints not satisfied"); + static_assert(view::value, "Constraints not satisfied"); + static_assert(input_range>::value, "Constraints not satisfied"); + static_assert(view::value, "Constraints not satisfied"); + static_assert(detail::join_with_compatible, Pattern>::value, "Constraints not satisfied"); + + template class iterator; + template friend class iterator; + template class sentinel; + template friend class sentinel; + + template + class iterator + : public detail::join_with_view_iterator_base< + maybe_const, + range_reference_t>, + maybe_const> + { + using iterator_base = detail::join_with_view_iterator_base< + maybe_const, + range_reference_t>, + maybe_const>; + + friend class join_with_view; + template friend class sentinel; + + using Parent = maybe_const; + using Base = maybe_const; + using InnerBase = range_reference_t; + using PatternBase = maybe_const; + + using OuterIter = iterator_t; + using InnerIter = iterator_t; + using PatternIter = iterator_t; + + public: + using value_type = common_type_t, range_value_t>; + using difference_type = common_type_t< + range_difference_t, + range_difference_t, + range_difference_t>; +#if __cplusplus < 202002L + using pointer = void; + using reference = common_reference_t, range_reference_t>; +#endif + + iterator() = default; + + template, + convertible_to, iterator_t>, + convertible_to>, iterator_t>, + convertible_to, iterator_t> + >::value, int> = 0> + constexpr iterator(iterator i) + : iterator_base(std::move(i.outer_it_)), parent_(i.parent_) { + switch (i.inner_it_.index()) { + case 0: + inner_it_.template emplace<0>(std::move( + vccc::detail::variant_raw_get(i.inner_it_._base().union_, in_place_index<0>))); + break; + case 1: + inner_it_.template emplace<1>(std::move( + vccc::detail::variant_raw_get(i.inner_it_._base().union_, in_place_index<1>))); + break; + default: + throw bad_variant_access{}; + } + } + + constexpr decltype(auto) operator*() const { + using reference = common_reference_t, range_reference_t>; + return inner_it_.visit([](auto&& it) -> reference { return *it; }); + } + + constexpr iterator& operator++() { + inner_it_.visit([](auto& it) { ++it; }); + satisfy(); + return *this; + } + + template, + forward_iterator, + forward_iterator + >::value == false, int> = 0> + constexpr void operator++(int) { + ++*this; + } + + template, + forward_iterator, + forward_iterator + >::value, int> = 0> + constexpr iterator operator++(int) { + auto tmp = *this; + ++*this; + return tmp; + } + + template, + bidirectional_range, + bidirectional_range, + common_range, + bidirectional_range, + common_range + >::value, int> = 0> + constexpr iterator& operator--() { + using namespace vccc::rel_ops; + + auto& outer_it = get_outer(); + if (outer_it == ranges::end(parent_->base_)) { + --outer_it; + inner_it_.template emplace<1>(ranges::end(get_inner())); + } + + for (;;) { + if (inner_it_.index() == 0) { + auto& it = vccc::detail::variant_raw_get(inner_it_._base().union_, in_place_index<0>); + if (it == ranges::begin(parent_->pattern_)) { + --outer_it; + inner_it_.template emplace<1>(ranges::end(get_inner())); + } else { + break; + } + } else if (inner_it_.index() == 1) { + auto& it = vccc::detail::variant_raw_get(inner_it_._base().union_, in_place_index<1>); + if (it == ranges::begin(get_inner())) { + inner_it_.template emplace<0>(ranges::end(parent_->pattern_)); + } else { + break; + } + } else { + throw bad_variant_access{}; + } + } + + inner_it_.visit([](auto& it) { --it; }); + return *this; + } + + + template, + bidirectional_range, + bidirectional_range, + common_range, + bidirectional_range, + common_range + >::value, int> = 0> + constexpr iterator operator--(int) { + auto tmp = *this; + --*this; + return tmp; + } + + template, + forward_range, + equality_comparable + >::value, int> = 0> + friend constexpr bool operator==(const iterator& x, const iterator& y) { + if (x.outer_it_ != y.outer_it_) { + return false; + } + + return x.inner_it_ == y.inner_it_; + } + + template, + forward_range, + equality_comparable + >::value, int> = 0> + friend constexpr bool operator!=(const iterator& x, const iterator& y) { + return !(x == y); + } + + private: + template::value, int> = 0> + constexpr iterator(Parent& parent, iterator_t outer_it) + : iterator_base(std::move(outer_it)), parent_(vccc::addressof(parent)) + { + using namespace vccc::rel_ops; + if (this->outer_it_ != ranges::end(parent_->base_)) { + inner_it_.template emplace<1>(ranges::begin(update_inner())); + satisfy(); + } + } + + template::value == false, int> = 0> + constexpr iterator(Parent& parent) + : parent_(vccc::addressof(parent)) + { + using namespace vccc::rel_ops; + if (*parent_->outer_it_ != ranges::end(parent_->base_)) { + inner_it_.template emplace<1>(ranges::begin(update_inner())); + satisfy(); + } + } + + template::value, int> = 0> + constexpr iterator_t& get_outer() noexcept { + return this->outer_it_; + } + + template::value == false, int> = 0> + constexpr iterator_t& get_outer() noexcept { + return *parent_->outer_it_; + } + + template::value, int> = 0> + constexpr const iterator_t& get_outer() const noexcept { + return this->outer_it_; + } + + template::value == false, int> = 0> + constexpr const iterator_t& get_outer() const noexcept { + return *parent_->outer_it_; + } + + template::value, int> = 0> + constexpr auto& update_inner() { + return *get_outer(); + } + + template::value == false, int> = 0> + constexpr auto& update_inner() { + return parent_->inner_base_.emplace_deref(get_outer()).val; + } + + template::value, int> = 0> + constexpr auto& get_inner() noexcept { + return *get_outer(); + } + + template::value == false, int> = 0> + constexpr auto& get_inner() noexcept { + return *parent_->inner_base_.val; + } + + constexpr void satisfy() { + using namespace vccc::rel_ops; + + for (;;) { + if (inner_it_.index() == 0) { + if (vccc::detail::variant_raw_get(inner_it_._base().union_, in_place_index<0>) != ranges::end(parent_->pattern_)) { + break; + } + + inner_it_.template emplace<1>(ranges::begin(update_inner())); + } else { + if (vccc::detail::variant_raw_get(inner_it_._base().union_, in_place_index<1>) != ranges::end(get_inner())) { + break; + } + + auto& outer_it = get_outer(); + ++outer_it; + if (outer_it == ranges::end(parent_->base_)) { + emplace_first_or_not(); + break; + } + + inner_it_.template emplace<0>(ranges::begin(parent_->pattern_)); + } + } + } + + template::value, int> = 0> + constexpr void emplace_first_or_not() { + inner_it_.template emplace<0>(); + } + + template::value == false, int> = 0> + constexpr void emplace_first_or_not() { /* no op */ } + + Parent* parent_{}; + variant, iterator_t> inner_it_{}; + }; + + template + class sentinel { + friend class join_with_view; + + using Parent = maybe_const; + using Base = maybe_const; + + public: + sentinel() = default; + + template, + convertible_to, sentinel_t> + >::value, int> = 0> + constexpr sentinel(sentinel i) + : end_(std::move(i.end_)) {} + + friend constexpr bool operator==(const iterator& x, const sentinel& y) { + return y.equal(x); + } + + friend constexpr bool operator!=(const iterator& x, const sentinel& y) { + return !(x == y); + } + + friend constexpr bool operator==(const sentinel& y, const iterator& x) { + return y.equal(x); + } + + friend constexpr bool operator!=(const sentinel& y, const iterator& x) { + return !(x == y); + } + + private: + constexpr explicit sentinel(Parent& parent) + : end_(ranges::end(parent.base_)) {} + + constexpr bool equal(const iterator& x) { + using namespace vccc::rel_ops; + return x.get_outer() == end_; + } + + sentinel_t end_{}; + }; + + join_with_view() = default; + + constexpr explicit join_with_view(V base, Pattern pattern) + : base_(std::move(base)), pattern_(std::move(pattern)) {} + + template>, + constructible_from>>> + >::value, int> = 0> + constexpr explicit join_with_view(R&& r, range_value_t> e) + : base_(views::all(std::forward(r))), pattern_(views::single(std::move(e))) {} + + + template::value, int> = 0> + constexpr V base() const& { + return base_; + } + + constexpr V base() && { + return std::move(base_); + } + + template::value, int> = 0> + constexpr auto begin() { + using Const = conjunction< + detail::simple_view, + detail::simple_view, + std::is_reference> + >; + return iterator{*this, ranges::begin(base_)}; + } + + template::value == false, int> = 0> + constexpr iterator begin() { + this->outer_it_.emplace(ranges::begin(base_)); + return iterator{*this}; + } + + template, + forward_range, + std::is_reference> + >::value, int> = 0> + constexpr iterator begin() const { + return iterator{*this, ranges::begin(base_)}; + } + + template, + std::is_reference>, + forward_range>, + common_range, + common_range> + >::value, int> = 0> + constexpr auto end() { + using simple = conjunction, detail::simple_view>; + return iterator{*this, ranges::end(base_)}; + } + + template, + std::is_reference>, + forward_range>, + common_range, + common_range> + >::value == false, int> = 0> + constexpr auto end() { + using simple = conjunction, detail::simple_view>; + return sentinel{*this}; + } + + template, + forward_range, + std::is_reference> + >::value, int> = 0> + constexpr auto end() const { + return end_impl(conjunction< + forward_range>, + common_range, + common_range> + >{}); + } + + private: + constexpr auto end_impl(std::true_type) const { + return iterator{*this, ranges::end(base_)}; + } + constexpr auto end_impl(std::false_type) const { + return sentinel{*this}; + } + + V base_; + Pattern pattern_; +}; + +#if __cplusplus >= 201703L + +template +join_with_view(R&&, P&&) -> join_with_view, views::all_t

>; + +template +join_with_view(R&&, range_value_t>) + -> join_with_view, single_view>>>; + +#endif + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_JOIN_WITH_VIEW_HPP_ diff --git a/include/vccc/__ranges/views/maybe_const.hpp b/include/vccc/__ranges/views/maybe_const.hpp deleted file mode 100644 index 11e80fd4..00000000 --- a/include/vccc/__ranges/views/maybe_const.hpp +++ /dev/null @@ -1,21 +0,0 @@ -// -// Created by YongGyu Lee on 1/26/24. -// - -#ifndef VCCC_RANGES_VIEWS_MAYBE_CONST_HPP -#define VCCC_RANGES_VIEWS_MAYBE_CONST_HPP - -#include - -namespace vccc { -namespace ranges { -namespace detail { - -template -using maybe_const = std::conditional_t; - -} // namespace detail -} // namespace ranges -} // namespace vccc - -#endif // VCCC_RANGES_VIEWS_MAYBE_CONST_HPP diff --git a/include/vccc/__ranges/views/reverse.hpp b/include/vccc/__ranges/views/reverse.hpp new file mode 100644 index 00000000..3a68fd92 --- /dev/null +++ b/include/vccc/__ranges/views/reverse.hpp @@ -0,0 +1,82 @@ +// +// Created by yonggyulee on 2/3/24. +// + +#ifndef VCCC_RANGES_VIEWS_REVERSE_HPP +#define VCCC_RANGES_VIEWS_REVERSE_HPP + +#include +#include +#include + +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__ranges/range_adaptor_closure.hpp" +#include "vccc/__ranges/subrange.hpp" +#include "vccc/__ranges/viewable_range.hpp" +#include "vccc/__ranges/views/all.hpp" +#include "vccc/__ranges/views/reverse_view.hpp" +#include "vccc/__type_traits/detail/return_category.hpp" +#include "vccc/__type_traits/is_specialization.hpp" +#include "vccc/__type_traits/remove_cvref.hpp" + +namespace vccc { +namespace ranges { +namespace views { +namespace detail { + +using vccc::detail::return_category; + +class reverse_adaptor_object : public range_adaptor_closure { + template + struct is_reverse_subrange : return_category<0> {}; + template + struct is_reverse_subrange, std::reverse_iterator, K>> + : return_category<2, subrange> {}; + + template + using reverse_tag = std::conditional_t< + is_specialization, reverse_view>::value, return_category<1>, + is_reverse_subrange> + >; + + template + constexpr auto call(R&& r, return_category<1>) const { + return std::forward(r).base())>(std::forward(r).base()); + } + + template + constexpr auto call(R&& r, return_category<2, subrange>) const { + return subrange(r.end().base(), r.begin().base(), r.size()); + } + + template + constexpr auto call(R&& r, return_category<2, subrange>) const { + return subrange(r.end().base(), r.begin().base()); + } + + template + constexpr auto call(R&& r, return_category<0>) const { + return reverse_view>(std::forward(r)); + } + + public: + template::value, int> = 0> + constexpr auto operator()(R&& r) const { + return call(std::forward(r), reverse_tag{}); + } +}; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::reverse_adaptor_object reverse{}; + +/// @} + +} // namespace views +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_REVERSE_HPP diff --git a/include/vccc/__ranges/views/reverse_view.hpp b/include/vccc/__ranges/views/reverse_view.hpp new file mode 100644 index 00000000..25f3ed0e --- /dev/null +++ b/include/vccc/__ranges/views/reverse_view.hpp @@ -0,0 +1,133 @@ +// +// Created by yonggyulee on 2/8/24. +// + +#ifndef VCCC_RANGES_VIEWS_REVERSE_VIEW_HPP +#define VCCC_RANGES_VIEWS_REVERSE_VIEW_HPP + +#include +#include +#include + +#include "vccc/__concepts/copy_constructible.hpp" +#include "vccc/__iterator/next.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/bidirectional_range.hpp" +#include "vccc/__ranges/common_range.hpp" +#include "vccc/__ranges/enable_borrowed_range.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__ranges/non_propagating_cache.hpp" +#include "vccc/__ranges/view.hpp" +#include "vccc/__ranges/views/all.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +template::value /* true; no cache */> +struct reverse_view_cached_begin { + constexpr std::reverse_iterator> begin(V& base) { + return std::make_reverse_iterator(ranges::end(base)); + } +}; + +template +struct reverse_view_cached_begin { + constexpr std::reverse_iterator> begin(V& base) { + if (!cached_begin_.has_value()) { + cached_begin_.emplace(std::make_reverse_iterator(ranges::next(ranges::begin(base), ranges::end(base)))); + } + return cached_begin_.value(); + } + + non_propagating_cache>> cached_begin_; +}; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +/** +@brief A \ref ranges::range "range" adaptor that represents a view of underlying \ref ranges::view "view" with reversed +order. + */ +template +class reverse_view + : public view_interface> + , private detail::reverse_view_cached_begin +{ + using cache_begin_base = detail::reverse_view_cached_begin; + public: + static_assert(view::value, "Constraints not satisfied"); + static_assert(bidirectional_range::value, "Constraints not satisfied"); + + reverse_view() = default; + + constexpr reverse_view(V r) + : base_(std::move(r)) {} + + template::value, int> = 0> + constexpr V base() const& { + return base_; + } + + constexpr V base() && { + return std::move(base_); + } + + constexpr std::reverse_iterator> begin() { + return cache_begin_base::begin(base_); + } + + template::value, int> = 0> + constexpr auto begin() const { + return std::make_reverse_iterator(ranges::end(base_)); + } + + constexpr std::reverse_iterator> end() { + return std::make_reverse_iterator(ranges::begin(base_)); + } + + template::value, int> = 0> + constexpr auto end() const { + return std::make_reverse_iterator(ranges::begin(base_)); + } + + template::value, int> = 0> + constexpr auto size() { + return ranges::size(base_); + } + + template::value, int> = 0> + constexpr auto size() const { + return ranges::size(base_); + } + + private: + V base_{}; +}; + +#if __cplusplus >= 201703L + +template +reverse_view(R&&) -> reverse_view>; + +#endif + +template +constexpr reverse_view> make_reverse_view(R&& r) { + return reverse_view>(std::forward(r)); +} + +template +struct enable_borrowed_range> : enable_borrowed_range {}; + + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_REVERSE_VIEW_HPP diff --git a/include/vccc/__ranges/views/split.hpp b/include/vccc/__ranges/views/split.hpp index fb7e63e0..12796900 100644 --- a/include/vccc/__ranges/views/split.hpp +++ b/include/vccc/__ranges/views/split.hpp @@ -26,14 +26,17 @@ namespace detail { template class split_adapter_closure : public range_adaptor_closure> { + template::value /* true */> + struct pattern_type_impl { + using type = single_view>; + }; template - using pattern_type = - std::conditional_t< - ranges::detail::same_with_range_value::value, - single_view>, - all_t - >; + struct pattern_type_impl { + using type = all_t; + }; + template + using pattern_type = typename pattern_type_impl::type; movable_box pattern_; public: diff --git a/include/vccc/__ranges/views/take.hpp b/include/vccc/__ranges/views/take.hpp index e7f84f8c..a2f774c9 100644 --- a/include/vccc/__ranges/views/take.hpp +++ b/include/vccc/__ranges/views/take.hpp @@ -89,12 +89,7 @@ struct take_niebloid { using category = return_category<0>; }; - template - struct is_subrange : std::false_type {}; - template - struct is_subrange> : std::true_type {}; - - template::value /* true */> + template::value /* true */> struct return_category_subrange : std::true_type { using category = return_category<2, subrange>>; }; @@ -107,9 +102,8 @@ struct take_niebloid { constexpr U operator()(R&& e, range_difference_t f, return_category<2, U>) const { using D = range_difference_t; return U( - ranges::begin(std::forward(e)), - ranges::begin(std::forward(e)) - + (std::min)(ranges::distance(std::forward(e)), f) + ranges::begin(e), + ranges::begin(e) + (std::min)(ranges::distance(e), f) ); } @@ -125,9 +119,8 @@ struct take_niebloid { constexpr IV operator()(R&& e, ranges::range_difference_t f, return_category<3, IV>) const { using D = ranges::range_difference_t; return IV( - *ranges::begin(std::forward(e)), - *(ranges::begin(std::forward(e)) - + (std::min)(ranges::distance(std::forward(e)), f)) + *ranges::begin(e), + *(ranges::begin(e) + (std::min)(ranges::distance(e), f)) ); } diff --git a/include/vccc/__ranges/views/take_view.hpp b/include/vccc/__ranges/views/take_view.hpp index 17d401ce..1a0fd1b3 100644 --- a/include/vccc/__ranges/views/take_view.hpp +++ b/include/vccc/__ranges/views/take_view.hpp @@ -78,10 +78,10 @@ class take_view : public view_interface> { template, sentinel_for< sentinel_t, - iterator_t> > + iterator_t> > >::value, int> = 0> friend constexpr bool - operator==(const counted_iterator>>& y, const sentinel& x) { + operator==(const counted_iterator>>& y, const sentinel& x) { using namespace vccc::rel_ops; return y.count() == 0 || y.base() == x.end_; } @@ -89,10 +89,10 @@ class take_view : public view_interface> { template, sentinel_for< sentinel_t, - iterator_t> > + iterator_t> > >::value, int> = 0> friend constexpr bool - operator!=(const counted_iterator>>& y, const sentinel& x) { + operator!=(const counted_iterator>>& y, const sentinel& x) { using namespace vccc::rel_ops; return !(y == x); } diff --git a/include/vccc/__ranges/views/views.hpp b/include/vccc/__ranges/views/views.hpp index fc436811..d43fbc5f 100644 --- a/include/vccc/__ranges/views/views.hpp +++ b/include/vccc/__ranges/views/views.hpp @@ -12,9 +12,14 @@ #include "vccc/__ranges/views/basic_istream_view.hpp" #include "vccc/__ranges/views/cartesian_product.hpp" #include "vccc/__ranges/views/cartesian_product_view.hpp" +#include "vccc/__ranges/views/common.hpp" +#include "vccc/__ranges/views/common_view.hpp" +#include "vccc/__ranges/views/concat_view.hpp" #include "vccc/__ranges/views/counted.hpp" #include "vccc/__ranges/views/drop.hpp" #include "vccc/__ranges/views/drop_view.hpp" +#include "vccc/__ranges/views/drop_while.hpp" +#include "vccc/__ranges/views/drop_while_view.hpp" #include "vccc/__ranges/views/elements.hpp" #include "vccc/__ranges/views/elements_view.hpp" #include "vccc/__ranges/views/empty_view.hpp" @@ -25,9 +30,13 @@ #include "vccc/__ranges/views/iota_view.hpp" #include "vccc/__ranges/views/join.hpp" #include "vccc/__ranges/views/join_view.hpp" +#include "vccc/__ranges/views/join_with.hpp" +#include "vccc/__ranges/views/join_with_view.hpp" #include "vccc/__ranges/views/keys_view.hpp" #include "vccc/__ranges/views/repeat.hpp" #include "vccc/__ranges/views/repeat_view.hpp" +#include "vccc/__ranges/views/reverse.hpp" +#include "vccc/__ranges/views/reverse_view.hpp" #include "vccc/__ranges/views/single.hpp" #include "vccc/__ranges/views/split.hpp" #include "vccc/__ranges/views/split_view.hpp" diff --git a/include/vccc/__span/span.hpp b/include/vccc/__span/span.hpp index a5ceb03e..01fc1053 100644 --- a/include/vccc/__span/span.hpp +++ b/include/vccc/__span/span.hpp @@ -224,8 +224,8 @@ class span : private detail::span_storage_t { detail::span_ctor_range >::value, int> = 0> constexpr span(R&& range) - : base(ranges::data(std::forward(range)), - ranges::size(std::forward(range))) {} + : base(ranges::data(range), + ranges::size(range)) {} template { detail::span_ctor_range >::value, int> = 0> constexpr explicit span(R&& range) - : base(ranges::data(std::forward(range)), - ranges::size(std::forward(range))) {} + : base(ranges::data(range), + ranges::size(range)) {} // (8) (C++ 26) // explicit(extent != std::dynamic_extent) diff --git a/include/vccc/__tuple/common_type.hpp b/include/vccc/__tuple/common_type.hpp deleted file mode 100644 index 9dab656a..00000000 --- a/include/vccc/__tuple/common_type.hpp +++ /dev/null @@ -1,58 +0,0 @@ -// -// Created by yonggyulee on 2023/10/27. -// - -#ifndef VCCC_TUPLE_COMMON_TYPE_HPP -#define VCCC_TUPLE_COMMON_TYPE_HPP - -#include -#include - -#include "vccc/__tuple/tuple_like.hpp" -#include "vccc/__type_traits/common_type.hpp" - -namespace vccc { - -/** - * @addtogroup tuple - * @{ - * @defgroup group_common_type_tuple_like vccc::common_type - * @brief determines the common type of a tuple and a \ref tuple_like "\a tuple-like " type - * - * @code - * template< tuple-like TTuple, tuple-like UTuple > - * struct common_type; - * @endcode - * The common type of two \ref tuple_like "\a tuple-like " types is a `std::tuple` - * consists of the common types of all corresponding element type pairs of both types. - * - * @sa tuple_like: @copybrief tuple_like - * @sa group_common_type: @copybrief group_common_type - * @} - */ - -/// @addtogroup group_common_type_tuple_like -/// @{ - -namespace internal { - -template::value == std::tuple_size::value)> -struct common_type_impl; - -template -struct common_type_impl, std::tuple, true> { - using type = std::tuple...>; -}; - -} // namespace internal - -template -struct common_type, std::tuple> - : internal::common_type_impl, std::tuple> {}; - -/// @} - -} // namespace vccc - -#endif // VCCC_TUPLE_COMMON_TYPE_HPP diff --git a/include/vccc/__tuple/detail/apply.hpp b/include/vccc/__tuple/detail/apply.hpp index f7f3ad64..a19ec0ee 100644 --- a/include/vccc/__tuple/detail/apply.hpp +++ b/include/vccc/__tuple/detail/apply.hpp @@ -16,7 +16,7 @@ namespace internal { template constexpr inline decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence) { - return invoke(std::forward(f), std::get(std::forward(t))...); + return vccc::invoke(std::forward(f), std::get(std::forward(t))...); } } // namespace internal diff --git a/include/vccc/__tuple/tuple_fold.hpp b/include/vccc/__tuple/tuple_fold.hpp new file mode 100644 index 00000000..1c76bcd6 --- /dev/null +++ b/include/vccc/__tuple/tuple_fold.hpp @@ -0,0 +1,65 @@ +// +// Created by YongGyu Lee on 2/13/24. +// + +#ifndef VCCC_TUPLE_TUPLE_FOLD_HPP_ +#define VCCC_TUPLE_TUPLE_FOLD_HPP_ + +#include +#include +#include + +#include "vccc/__functional/invoke.hpp" +#include "vccc/__tuple/tuple_like.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/remove_cvref.hpp" + +namespace vccc { +namespace detail { + +template +constexpr auto tuple_fold_left_impl(Tuple&& tuple, T&& x, F&& f, std::integral_constant) { + return vccc::invoke( + std::forward(f), + std::forward(x), + std::get(std::forward(tuple)) + ); +} + +template +constexpr auto tuple_fold_left_impl(Tuple&& tuple, T&& x, F&& f, std::integral_constant) { + return tuple_fold_left_impl( + std::forward(tuple), + vccc::invoke( + std::forward(f), + std::forward(x), + std::get(std::forward(tuple)) + ), + std::forward(f), + std::integral_constant{} + ); +} + +} // namespace detail + +/// @addtogroup tuple +/// @{ + +/// @brief Left fold operation for each tuple elements +template +>::value, int> = 0> +constexpr auto tuple_fold_left(Tuple&& tuple, T&& init, F&& f) { + return detail::tuple_fold_left_impl>::value>( + std::forward(tuple), + std::forward(init), + std::forward(f), + std::integral_constant{} + ); +} + +/// @} + +} // namespace vccc + +#endif // VCCC_TUPLE_TUPLE_FOLD_HPP_ diff --git a/include/vccc/__tuple/tuple_like.hpp b/include/vccc/__tuple/tuple_like.hpp index 97630c24..c3df0628 100644 --- a/include/vccc/__tuple/tuple_like.hpp +++ b/include/vccc/__tuple/tuple_like.hpp @@ -32,6 +32,18 @@ struct tuple_size_equal_to : bool_constant::value == X> {}; template struct tuple_size_equal_to : std::false_type {}; +template::value> +struct tuple_size_greater_than : bool_constant<(std::tuple_size::value > X)> {}; + +template +struct tuple_size_greater_than : std::false_type {}; + +template::value> +struct tuple_size_less_than : bool_constant<(std::tuple_size::value < X)> {}; + +template +struct tuple_size_less_than : std::false_type {}; + template struct tuple_like_uncvref : std::false_type {}; @@ -80,6 +92,20 @@ template struct tuple_like : internal::tuple_like_uncvref> {}; +/** + * @brief check if tuple-like objects with exactly N elements. + * + * @par See Also + * @ref tuple_like "\a tuple-like ": @copybrief tuple_like + */ +template +struct sized_tuple_like + : conjunction< + tuple_like, + internal::tuple_size_equal_to + > {}; + + /** * @brief pair-like objects are tuple-like objects with exactly 2 elements. * @@ -87,9 +113,7 @@ struct tuple_like : internal::tuple_like_uncvref> {}; * @ref tuple_like "\a tuple-like ": @copybrief tuple_like */ template -struct pair_like - : conjunction, - internal::tuple_size_equal_to> {}; +using pair_like = sized_tuple_like; /// @} diff --git a/include/vccc/__tuple/tuple_transform.hpp b/include/vccc/__tuple/tuple_transform.hpp new file mode 100644 index 00000000..6cca494a --- /dev/null +++ b/include/vccc/__tuple/tuple_transform.hpp @@ -0,0 +1,40 @@ +// +// Created by YongGyu Lee on 2/20/24. +// + +#ifndef VCCC_TUPLE_TUPLE_TRANSFORM_HPP +#define VCCC_TUPLE_TUPLE_TRANSFORM_HPP + +#include +#include + +#include "vccc/__functional/invoke.hpp" +#include "vccc/__type_traits/remove_cvref.hpp" + +namespace vccc { +namespace detail { + +template +constexpr auto tuple_transform_impl(Tuple&& t, F&& f, std::index_sequence) { + return std::tuple(f), std::get(std::forward(t))))...>( + vccc::invoke(std::forward(f), std::get(std::forward(t)))...); +} + +} // namespace detail + +/// @addtogroup tuple +/// @{ + +/// @brief Constructs a new tuple with each elements transformed +template +constexpr auto tuple_transform(Tuple&& t, F&& f) { + return detail::tuple_transform_impl( + std::forward(t), std::forward(f), + std::make_index_sequence>::value>{}); +} + +/// @} + +} // namespace vccc + +#endif // VCCC_TUPLE_TUPLE_TRANSFORM_HPP diff --git a/include/vccc/__type_traits/common_type.hpp b/include/vccc/__type_traits/common_type.hpp index 5a9f3d4f..e8780ad7 100644 --- a/include/vccc/__type_traits/common_type.hpp +++ b/include/vccc/__type_traits/common_type.hpp @@ -5,8 +5,11 @@ #ifndef VCCC_TYPE_TRAITS_COMMON_TYPE_HPP #define VCCC_TYPE_TRAITS_COMMON_TYPE_HPP +#include #include +#include +#include "vccc/__tuple/tuple_like.hpp" #include "vccc/__type_traits/has_typename_type.hpp" #include "vccc/__type_traits/is_referenceable.hpp" #include "vccc/__type_traits/void_t.hpp" @@ -156,6 +159,47 @@ struct common_type_test_1>> : common_type_test_1_1 {}; +template +struct common_type_tuple_like_3 : common_type_test_1 {}; + +template class Tuple, typename... T, typename... U> +struct common_type_tuple_like_3, Tuple, true> { + using type = Tuple::type...>; +}; + +template< + typename T1, + typename T2, + bool = bool_constant<(std::tuple_size::value == std::tuple_size::value)>::value /* false */ +> +struct common_type_tuple_like_2 : common_type_test_1 {}; + +template class TTuple, template class UTuple, typename... T, typename... U> +struct common_type_tuple_like_2, UTuple, true> + : common_type_tuple_like_3< + TTuple, + UTuple, + conjunction< + has_typename_type>... + >::value + > {}; + +template< + typename T1, + typename T2, + bool = conjunction< + tuple_like, + tuple_like, + std::is_same>, + std::is_same> + >::value /* true */ +> +struct common_type_tuple_like : common_type_tuple_like_2 {}; + +template +struct common_type_tuple_like : common_type_test_1 {}; + + template struct common_type_test_three_or_more : no_common_type {}; @@ -172,7 +216,7 @@ template struct common_type : common_type {}; template -struct common_type : detail::common_type_test_1, std::decay_t> {}; +struct common_type : detail::common_type_tuple_like, std::decay_t> {}; template struct common_type @@ -184,6 +228,46 @@ struct common_type template using common_type_t = typename common_type::type; + +// Specialization for std +namespace detail { + +template +struct common_type_specialization_impl : no_common_type {}; + +template class C, typename... T, typename... U> +struct common_type_specialization_impl, C, true> { + using type = C...>; +}; + +template +struct common_type_specialization; + +template class C, typename... T, typename... U> +struct common_type_specialization, C> + : common_type_specialization_impl< + C, + C, + conjunction< + has_typename_type>... + >::value + > {}; + +} // namespace detail + +template +struct common_type, std::pair> + : detail::common_type_specialization, std::pair> {}; + +template +struct common_type, std::chrono::duration> + : detail::common_type_specialization, std::chrono::duration> {}; + +template +struct common_type, std::chrono::time_point> + : detail::common_type_specialization, std::chrono::time_point> {}; + + /// @} } // namespace vccc diff --git a/include/vccc/__type_traits/is_class_or_enum.hpp b/include/vccc/__type_traits/is_class_or_enum.hpp new file mode 100644 index 00000000..f402eeeb --- /dev/null +++ b/include/vccc/__type_traits/is_class_or_enum.hpp @@ -0,0 +1,27 @@ +// +// Created by yonggyulee on 2024/02/08. +// + +#ifndef VCCC_TYPE_TRAITS_IS_CLASS_OR_ENUM_HPP +#define VCCC_TYPE_TRAITS_IS_CLASS_OR_ENUM_HPP + +#include + +#include "vccc/__type_traits/disjunction.hpp" + +namespace vccc { + +//! @addtogroup type_traits +//! @{ +//! @addtogroup type_traits_is_class_or_enum__class__Type_properties is_class_or_enum +//! @{ + +template +struct is_class_or_enum : disjunction, std::is_enum> {}; + +/// @} +/// @} + +} // namespace vccc + +#endif // VCCC_TYPE_TRAITS_IS_CLASS_OR_ENUM_HPP diff --git a/include/vccc/__type_traits/maybe_const.hpp b/include/vccc/__type_traits/maybe_const.hpp new file mode 100644 index 00000000..7e8e397c --- /dev/null +++ b/include/vccc/__type_traits/maybe_const.hpp @@ -0,0 +1,17 @@ +// +// Created by YongGyu Lee on 1/26/24. +// + +#ifndef VCCC_TYPE_TRAITS_MAYBE_CONST_HPP +#define VCCC_TYPE_TRAITS_MAYBE_CONST_HPP + +#include + +namespace vccc { + +template +using maybe_const = std::conditional_t; + +} // namespace vccc + +#endif // VCCC_TYPE_TRAITS_MAYBE_CONST_HPP diff --git a/include/vccc/__utility/key_value.hpp b/include/vccc/__utility/key_value.hpp new file mode 100644 index 00000000..7717328f --- /dev/null +++ b/include/vccc/__utility/key_value.hpp @@ -0,0 +1,44 @@ +// +// Created by YongGyu Lee on 2/22/24. +// + +#ifndef VCCC_UTILITY_KEY_VALUE_HPP +#define VCCC_UTILITY_KEY_VALUE_HPP + +#include +#include +#include + +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__tuple/tuple_like.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/remove_cvref.hpp" + +namespace vccc { +namespace detail { + +template +struct element_niebloid { + template, + internal::tuple_size_greater_than, I> + >::value, int> = 0> + constexpr decltype(auto) operator()(T&& t) const noexcept { + return std::get(std::forward(t)); + } +}; + +} // namespace detail + +VCCC_INLINE_OR_STATIC constexpr detail::element_niebloid<0> key; +VCCC_INLINE_OR_STATIC constexpr detail::element_niebloid<0> first; +VCCC_INLINE_OR_STATIC constexpr detail::element_niebloid<1> value; +VCCC_INLINE_OR_STATIC constexpr detail::element_niebloid<1> second; + +template +VCCC_INLINE_OR_STATIC constexpr detail::element_niebloid element; + +} // namespace vccc + + +#endif // VCCC_UTILITY_KEY_VALUE_HPP diff --git a/include/vccc/__utility/type_sequence.hpp b/include/vccc/__utility/type_sequence.hpp index 875a631a..e7a5c767 100644 --- a/include/vccc/__utility/type_sequence.hpp +++ b/include/vccc/__utility/type_sequence.hpp @@ -119,6 +119,9 @@ struct type_sequence { template using element_type = type_sequence_element_type_t; + + using front = element_type<0>; + using back = element_type; }; /// @} diff --git a/include/vccc/__variant/variant.hpp b/include/vccc/__variant/variant.hpp index db0e5872..d45c32c7 100644 --- a/include/vccc/__variant/variant.hpp +++ b/include/vccc/__variant/variant.hpp @@ -581,6 +581,8 @@ constexpr decltype(auto) visit_single(Visitor&& vis, Variant&& var); template constexpr R visit_single(Visitor&& vis, Variant&& var); +struct variant_valueless_ctor {}; + } // namespace detail template @@ -594,6 +596,11 @@ class variant : private detail::variant_control_smf { static_assert(disjunction...>::value == false, "Type must not be a reference"); static_assert(disjunction...>::value == false, "Type must not be a void"); + /// @cond ignored + constexpr explicit variant(detail::variant_valueless_ctor) noexcept + : base() {} + /// @endcond + template, std::is_default_constructible> >::value, int> = 0> @@ -736,10 +743,12 @@ class variant : private detail::variant_control_smf { return detail::visit_single(std::forward(vis), std::move(*this)); } + /// @cond ignored detail::variant_base& _base() & { return static_cast&>(*this); } detail::variant_base&& _base() && { return static_cast&&>(*this); } const detail::variant_base& _base() const & { return static_cast&>(*this); } const detail::variant_base&& _base() const && { return static_cast&&>(*this); } + /// @endcond private: struct visitor_self { diff --git a/include/vccc/algorithm.hpp b/include/vccc/algorithm.hpp index 05d286c9..b5277471 100644 --- a/include/vccc/algorithm.hpp +++ b/include/vccc/algorithm.hpp @@ -27,6 +27,7 @@ #include "vccc/__algorithm/ranges/in_out_out_result.hpp" #include "vccc/__algorithm/ranges/in_out_result.hpp" #include "vccc/__algorithm/ranges/in_value_result.hpp" +#include "vccc/__algorithm/ranges/lexicographical_compare.hpp" #include "vccc/__algorithm/ranges/max.hpp" #include "vccc/__algorithm/ranges/max_element.hpp" #include "vccc/__algorithm/ranges/min.hpp" diff --git a/include/vccc/concepts.hpp b/include/vccc/concepts.hpp index 061c67bf..5532a2da 100644 --- a/include/vccc/concepts.hpp +++ b/include/vccc/concepts.hpp @@ -18,6 +18,7 @@ #include "vccc/__concepts/dereferenceable.hpp" #include "vccc/__concepts/derived_from.hpp" #include "vccc/__concepts/derived_from_single_crtp.hpp" +#include "vccc/__concepts/different_from.hpp" #include "vccc/__concepts/equality_comparable.hpp" #include "vccc/__concepts/equivalence_relation.hpp" #include "vccc/__concepts/floating_point.hpp" diff --git a/include/vccc/iterator.hpp b/include/vccc/iterator.hpp index ac0dcb57..4bb302c1 100644 --- a/include/vccc/iterator.hpp +++ b/include/vccc/iterator.hpp @@ -19,6 +19,7 @@ #include "vccc/__iterator/advance.hpp" #include "vccc/__iterator/basic_const_iterator.hpp" #include "vccc/__iterator/bidirectional_iterator.hpp" +#include "vccc/__iterator/common_iterator.hpp" #include "vccc/__iterator/contiguous_iterator.hpp" #include "vccc/__iterator/counted_iterator.hpp" #include "vccc/__iterator/default_sentinel_t.hpp" diff --git a/include/vccc/memory.hpp b/include/vccc/memory.hpp new file mode 100644 index 00000000..7b66cb50 --- /dev/null +++ b/include/vccc/memory.hpp @@ -0,0 +1,11 @@ +// +// Created by yonggyulee on 2/7/24. +// + +#ifndef VCCC_MEMORY_HPP_ +#define VCCC_MEMORY_HPP_ + +#include "vccc/__memory/addressof.hpp" +#include "vccc/__memory/to_address.hpp" + +#endif // VCCC_MEMORY_HPP_ diff --git a/include/vccc/ranges.hpp b/include/vccc/ranges.hpp index 0b942cd0..932b4c3b 100644 --- a/include/vccc/ranges.hpp +++ b/include/vccc/ranges.hpp @@ -43,7 +43,9 @@ #include "vccc/__ranges/range_rvalue_reference_t.hpp" #include "vccc/__ranges/range_size_t.hpp" #include "vccc/__ranges/range_value_t.hpp" +#include "vccc/__ranges/rbegin.hpp" #include "vccc/__ranges/ref_view.hpp" +#include "vccc/__ranges/rend.hpp" #include "vccc/__ranges/size.hpp" #include "vccc/__ranges/sized_range.hpp" #include "vccc/__ranges/ssize.hpp" diff --git a/include/vccc/tuple.hpp b/include/vccc/tuple.hpp index d9e916a3..8a09ddb9 100644 --- a/include/vccc/tuple.hpp +++ b/include/vccc/tuple.hpp @@ -6,9 +6,10 @@ # define VCCC_TUPLE_HPP # # include "vccc/__tuple/apply.hpp" -# include "vccc/__tuple/common_type.hpp" # include "vccc/__tuple/make_from_tuple.hpp" +# include "vccc/__tuple/tuple_fold.hpp" # include "vccc/__tuple/tuple_like.hpp" +# include "vccc/__tuple/tuple_transform.hpp" /** @defgroup tuple tuple diff --git a/include/vccc/type_traits.hpp b/include/vccc/type_traits.hpp index 97a32b79..355d05eb 100644 --- a/include/vccc/type_traits.hpp +++ b/include/vccc/type_traits.hpp @@ -30,6 +30,7 @@ # include "vccc/__type_traits/has_typename_type.hpp" # include "vccc/__type_traits/has_typename_value_type.hpp" # include "vccc/__type_traits/is_bounded_array.hpp" +# include "vccc/__type_traits/is_class_or_enum.hpp" # include "vccc/__type_traits/is_complete.hpp" # include "vccc/__type_traits/is_explicitly_constructible.hpp" # include "vccc/__type_traits/is_explicitly_convertible.hpp" @@ -49,6 +50,7 @@ # include "vccc/__type_traits/is_unbounded_array.hpp" # include "vccc/__type_traits/iterable.hpp" # include "vccc/__type_traits/lossless_type.hpp" +# include "vccc/__type_traits/maybe_const.hpp" # include "vccc/__type_traits/negation.hpp" # include "vccc/__type_traits/numeric.hpp" # include "vccc/__type_traits/remove_cvref.hpp" diff --git a/include/vccc/utility.hpp b/include/vccc/utility.hpp index c05cf41e..6f46457b 100644 --- a/include/vccc/utility.hpp +++ b/include/vccc/utility.hpp @@ -10,6 +10,7 @@ # include "vccc/__utility/compressed_pair.hpp" # include "vccc/__utility/cxx20_rel_ops.hpp" # include "vccc/__utility/in_place.hpp" +# include "vccc/__utility/key_value.hpp" # include "vccc/__utility/nontype.hpp" # include "vccc/__utility/sequence.hpp" # include "vccc/__utility/time.hpp" diff --git a/test/algorithm_test.cpp b/test/algorithm_test.cpp index 964a438d..ba4b6e3c 100644 --- a/test/algorithm_test.cpp +++ b/test/algorithm_test.cpp @@ -154,6 +154,18 @@ int Test() { TEST_ENSURES(found5 && vccc::ranges::distance(haystack.begin(), found5.begin()) == 1); } + { // ranges::lexicographical_compare + std::cout << "Line " << __LINE__ << ", ranges::lexicographical_compare:\n"; + + std::vector v1 {'a', 'b', 'c', 'd'}; + std::vector v2 {'a', 'b', 'c', 'd'}; + + TEST_ENSURES(ranges::lexicographical_compare(v1, v2) == false); + TEST_ENSURES(ranges::lexicographical_compare("dabc"_sv, "cbda"_sv) == false); + TEST_ENSURES(ranges::lexicographical_compare("bdac"_sv, "adcb"_sv) == false); + TEST_ENSURES(ranges::lexicographical_compare("acdb"_sv, "cdab"_sv) == true); + } + return TEST_RETURN_RESULT; } diff --git a/test/ranges_test.cpp b/test/ranges_test.cpp index 97c935c0..19da7591 100644 --- a/test/ranges_test.cpp +++ b/test/ranges_test.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,7 @@ #include "vccc/span.hpp" #include "vccc/string_view.hpp" #include "vccc/type_traits.hpp" +#include "vccc/utility.hpp" #include "test_core.hpp" struct IntLike { @@ -122,7 +124,7 @@ int main() { vccc::ranges::swap(d1, d2); } - { + { // ranges::size int array[] = {1, 2, 3}; std::vector v = {4, 5, 6}; auto il = {7}; @@ -141,7 +143,7 @@ int main() { } - { + { // ranges::empty int array[] = {1, 2, 3}; std::vector v = {4, 5, 6}; auto il = {7}; @@ -157,7 +159,44 @@ int main() { vccc::ranges::empty(i); } - { + { // ranges::rbegin + std::cout << "Line " << __LINE__ << ", ranges::rbegin: \n"; + + std::vector v = {3, 1, 4}; + auto vi = vccc::ranges::rbegin(v); + TEST_ENSURES(*vi == 4); + *vi = 42; // OK + TEST_ENSURES(v.back() == 42); + + int a[] = {-5, 10, 15}; + auto ai = vccc::ranges::rbegin(a); + TEST_ENSURES(*ai == 15); + *ai = 42; // OK + TEST_ENSURES(a[2] == 42); + + // auto x_x = std::ranges::rbegin(std::vector{6, 6, 6}); + // ill-formed: the argument is an rvalue (see Notes above) + + auto si = vccc::ranges::rbegin(vccc::span(a)); // OK + static_assert(vccc::ranges::enable_borrowed_range< + std::remove_cv_t(a))>>::value, ""); + *si = 52; // OK + TEST_ENSURES(a[2] == 52); + } + + { // ranges::rend + std::cout << "Line " << __LINE__ << ", ranges::rend: \n"; + + std::vector v = {3, 1, 4}; + namespace ranges = vccc::ranges; + TEST_ENSURES((ranges::find(ranges::rbegin(v), ranges::rend(v), 5) == ranges::rend(v))); + + int a[] = {5, 10, 15}; + TEST_ENSURES((ranges::find(ranges::rbegin(a), ranges::rend(a), 5) != ranges::rend(a))); + } + + { // ranges::iota_view, views::iota + std::cout << "Line " << __LINE__ << ", ranges::iota_view, views::iota: \n"; for (int i : vccc::ranges::iota_view{1, 10}) std::cout << i << ' '; @@ -528,7 +567,7 @@ int main() { #if __cplusplus < 201703L for (const auto p : vccc::views::enumerate(v)) - std::cout << '(' << std::get<0>(p) << ':' << std::get<1>(p) << ") "; + std::cout << '(' << vccc::first(p) << ':' << vccc::second(p) << ") "; #else for (auto const [index, letter] : vccc::views::enumerate(v)) std::cout << '(' << index << ':' << letter << ") "; @@ -542,7 +581,7 @@ int main() { #if __cplusplus < 201703L for (const auto kv : m) - std::cout << '[' << std::get<0>(kv) << "]:" << std::get<1>(kv) << ' '; + std::cout << '[' << vccc::key(kv) << "]:" << vccc::value(kv) << ' '; #else for (auto const [key, value] : m) std::cout << '[' << key << "]:" << value << ' '; @@ -559,7 +598,7 @@ int main() { #if __cplusplus < 201703L for (const auto i_n : vccc::views::enumerate(numbers)) { - ++std::get<1>(i_n); + ++vccc::value(i_n); std::cout << numbers[std::get<0>(i_n)] << ' '; } #else @@ -571,6 +610,35 @@ int main() { std::cout << '\n'; } + { // views::enumerate_struct + constexpr static auto v = {'A', 'B', 'C', 'D'}; + + for (const auto p : vccc::views::enumerate_pair(v)) + std::cout << '(' << p.first << ':' << p.second << ") "; + std::cout << std::endl; + TEST_ENSURES(vccc::views::enumerate_pair(v).size() == 4); + TEST_ENSURES(vccc::views::enumerate_pair(v).begin().index() == 0); + TEST_ENSURES((vccc::views::enumerate_pair(v).end() - 1).index() == 3); + + + auto m = v | vccc::views::enumerate_pair | vccc::ranges::to(); + + TEST_ENSURES(m.size() == 4); + TEST_ENSURES(m[0] == 'A'); + TEST_ENSURES(m[1] == 'B'); + TEST_ENSURES(m[2] == 'C'); + TEST_ENSURES(m[3] == 'D'); + + + std::vector numbers{1, 3, 5, 7}; + + for (const auto i_n : vccc::views::enumerate_pair(numbers)) { + ++i_n.second; + std::cout << numbers[i_n.first] << ' '; + } + std::cout << '\n'; + } + { // filter_view auto even = [](int i) { return 0 == i % 2; }; auto square = [](int i) { return i * i; }; @@ -751,6 +819,15 @@ int main() { static_assert(std::is_same< decltype(w2), vccc::ranges::split_view> >::value, ""); + + std::string s = "path/to/my/file.foo.bar"; + + auto splitted = s | vccc::views::split('/') | vccc::ranges::to>(); + TEST_ENSURES(splitted.size() == 4); + TEST_ENSURES(splitted[0] == "path"); + TEST_ENSURES(splitted[1] == "to"); + TEST_ENSURES(splitted[2] == "my"); + TEST_ENSURES(splitted[3] == "file.foo.bar"); } { @@ -854,5 +931,187 @@ int main() { } } + { // common_view, common + { + auto v1 = {1, 2, 3, 4, 5}; + auto i1 = vccc::counted_iterator{v1.begin(), vccc::ssize(v1)}; + auto r1 = vccc::ranges::subrange{i1, vccc::default_sentinel}; + // auto e1 = std::accumulate(r1.begin(), r1.end(), 0); // error: "common range" required + auto c1 = vccc::ranges::make_common_view(r1); + TEST_ENSURES((std::accumulate(c1.begin(), c1.end(), 0) == 15)); + // + // // inherited from ranges::view_interface: + TEST_ENSURES(c1.front() == 1); + TEST_ENSURES(c1.back() == 5); + std::cout << "c1.data(): " << c1.data() << '\n'; + TEST_ENSURES(c1[0] == 1); + + auto v2 = std::list{1, 2, 3, 4, 5}; + auto i2 = vccc::counted_iterator{v2.begin(), vccc::ssize(v2)}; + auto r2 = vccc::ranges::subrange{i2, vccc::default_sentinel}; + // auto e2 = std::accumulate(r2.begin(), r2.end(), 0); // error: "common range" required + auto c2 = vccc::ranges::make_common_view(r2); + TEST_ENSURES((std::accumulate(c2.begin(), c2.end(), 0) == 15)); + + // inherited from ranges::view_interface: + std::cout << "c2.front(): " << c2.front() << '\n'; + TEST_ENSURES(c2.front() == 1); + // auto e3 = c2.back(); // error: "bidirectional range" required + // auto e4 = c2.data(); // error: "contiguous range" required + // auto e5 = c2[0]; // error: "random access range" required + } + + { + std::string str { "C++20" }; + auto view = vccc::views::common(str); + + std::string copy_of_str = view.base(); + TEST_ENSURES(copy_of_str == "C++20"); + TEST_ENSURES(view.base() == "C++20"); + + std::string move_str = std::move(view.base()); + TEST_ENSURES(move_str == "C++20"); + TEST_ENSURES(view.base() == vccc::string_view{}); + } + + { + constexpr auto common = vccc::views::iota(1) + | vccc::views::take(3) + | vccc::views::common + ; + int i = 0; + auto first = common.begin(), last = common.end(); + for (int e : common) + std::cout << (i++ ? " + " : "") << e; + + std::cout << " = " << std::accumulate(common.begin(), common.end(), 0) << '\n'; + TEST_ENSURES((std::accumulate(common.begin(), common.end(), 0) == 6)); + } + + { + constexpr int n{4}; + + constexpr auto v1 = vccc::views::iota(1) + | vccc::views::take(n) + | vccc::views::common + ; + constexpr auto v2 = vccc::views::iota(2) + | vccc::views::take(n) + ; + const int product = std::inner_product(v1.begin(), v1.end(), + v2.begin(), + 0); + TEST_ENSURES(product == 40); + } + + { + constexpr static auto v1 = {1, 2, 3, 4, 5}; + constexpr auto common1 { v1 | vccc::views::common }; + TEST_ENSURES(common1.size() == 5); + + constexpr auto take3 { v1 | vccc::views::reverse | vccc::views::take(3) }; + constexpr auto common2 { take3 | vccc::views::common }; + static_assert(common2.size() == 3, ""); + + constexpr static auto v2 = { "^"_sv, "v"_sv, "<"_sv, ">"_sv }; + TEST_ENSURES(vccc::ranges::views::common(v2).size() == 4); + } + } + + { // ranges::common_view, views::common + std::cout << "Line " << __LINE__ << ", ranges::common_view, views::common: \n"; + + static constexpr auto il = {3, 1, 4, 1, 5, 9}; + + auto rv = vccc::ranges::make_reverse_view(il); + for (int i : rv) + std::cout << i << ' '; + std::cout << '\n'; + TEST_ENSURES((vccc::ranges::equal(rv, {9, 5, 1, 4, 1, 3}))); + + for (int i : il | vccc::views::reverse) + std::cout << i << ' '; + std::cout << '\n'; + TEST_ENSURES((vccc::ranges::equal(il | vccc::views::reverse, {9, 5, 1, 4, 1, 3}))); + + // operator[] is inherited from std::view_interface + for (auto i{0U}; i != rv.size(); ++i) + std::cout << rv[i] << ' '; + std::cout << '\n'; + } + + { // ranges::join_with_view, views::join_with + std::cout << "Line " << __LINE__ << ", ranges::join_with_view, views::join_with: \n"; + + std::vector v{"This"_sv, "is"_sv, "a"_sv, "test."_sv}; + auto joined = vccc::views::join_with(v, ' '); + + TEST_ENSURES((vccc::ranges::equal(joined, "This is a test."_sv))); + auto s = joined | vccc::ranges::to(); + static_assert(vccc::same_as::value, ""); + TEST_ENSURES(s == "This is a test."); + } + + { + std::string a = "hello, "; + std::vector b = {'w', 'o', 'r', 'l', 'd', '!'}; + std::list c = {'?'}; + + auto catted = vccc::views::concat(a, b, c); + TEST_ENSURES(*catted.begin() == 'h'); + TEST_ENSURES(catted.size() == a.size() + b.size() + c.size()); + + TEST_ENSURES((vccc::ranges::equal(catted, "hello, world!?"_sv))); + + std::vector v1 = {1, 2, 3, 4, 5}; + for (const auto x : vccc::views::concat(v1, vccc::views::iota(100) | vccc::views::take(10) | vccc::views::common)) { + std::cout << x; + } + std::cout << '\n'; + } + + { // ranges::drop_while_view, views::drop_while + { + auto is_space = [](char q) { + static constexpr auto ws = {' ', '\t', '\n', '\v', '\r', '\f'}; + return vccc::ranges::any_of(ws, [q](auto p) { return p == q; }); + }; + + auto trim_left = [=](const vccc::string_view in) -> std::string { + auto view = in | vccc::views::drop_while(is_space); + return {view.begin(), view.end()}; + }; + + auto trim = [=](const vccc::string_view in) -> std::string { + auto view = in + | vccc::views::drop_while(is_space) | vccc::views::reverse + | vccc::views::drop_while(is_space) | vccc::views::reverse; + return {view.begin(), view.end()}; + }; + + TEST_ENSURES(trim_left(" \n C++23") == "C++23"_sv); + vccc::string_view src = " \f\n\t\r\vHello, C++20!\f\n\t\r\v "; + + const auto s = trim(src); + TEST_ENSURES(s == "Hello, C++20!"); + + static constexpr auto v = {0, 1, 2, 3, 4, 5}; + TEST_ENSURES(vccc::ranges::equal(v | vccc::views::drop_while([](int i) { return i < 3; }), vccc::views::iota(3, 6))); + } + { + constexpr std::array data{0, -1, -2, 3, 1, 4, 1, 5}; + auto view = vccc::ranges::make_drop_while_view(data, [](int x) { return x <= 0; }); + TEST_ENSURES(vccc::ranges::equal(view, vccc::span{3, 1, 4, 1, 5})); + + TEST_ENSURES(*view.begin() == 3); + TEST_ENSURES(view.front() == 3); + TEST_ENSURES(view.back() == 5); + TEST_ENSURES(view.size() == 5); + TEST_ENSURES(view[4] == 5); + TEST_ENSURES(!view.empty()); + TEST_ENSURES(bool(view)); + } + } + return TEST_RETURN_RESULT; } diff --git a/test/tuple_test.cpp b/test/tuple_test.cpp index cd781437..2adbc8da 100644 --- a/test/tuple_test.cpp +++ b/test/tuple_test.cpp @@ -4,9 +4,11 @@ #include #include +#include #include #include #include +#include #include "vccc/tuple.hpp" #include "test_core.hpp" @@ -37,6 +39,24 @@ int Test() { static_assert(pair_like>::value == true, " "); static_assert(pair_like>::value == false, " "); + { + auto t = std::make_tuple(1, 3.3f, 10.0); + auto sum = tuple_fold_left(t, 0.0, std::plus<>{}); + TEST_ENSURES(sum == 0.0 + 1 + 3.3f + 10.0); + } + + { + auto t = std::make_tuple(1, 2, 3); + auto sum = tuple_fold_left( + tuple_transform(t, [](auto x) { return x * 2; }), 0, std::plus<>{}); + TEST_ENSURES(sum == 12); + + auto t2 = std::make_tuple(std::vector{1, 2, 3}, std::string{"456"}, std::list{7, 8, 9}); + auto size_sum = tuple_fold_left( + tuple_transform(t2, [](auto&& r) { return r.size(); }), 0, std::plus<>{}); + TEST_ENSURES(size_sum == 9); + } + return TEST_RETURN_RESULT; }