From 60546c2c6d2bb088e60a7b687ce7e0103aeb2285 Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Mon, 27 May 2024 00:57:46 +0900 Subject: [PATCH] v2024.05 (#128) * Add tuple_for_each * Use maybe_const * Add views::zip, ranges::zip_view * Update zip_view.hpp * Update zip_view.hpp * Add to_array * Create three_way_comparable.hpp * Fix zip_view * Add zip_transfrom_view * Add find_last * Update zip_transform_view.hpp * Add ranges::find_end * Add ranges:: find_first_of * Update algorithm_test.cpp * Create debug_assert.hpp * Update doxy * Create ignore_dumb_diagnostics_pop.hpp * Create ignore_dumb_diagnostics_push.hpp * Update tuple_for_each.hpp * Update tuple_transform.hpp * Fix iter_move, iter_swap * Update iterator_test.cpp * Fix error * Update transform_view.hpp * Fix pragma warning * Update join_with_view.hpp * Update transform_view.hpp * Update transform_view.hpp * Update fold_left.hpp * Update non_propagating_cache.hpp * Update indirectly_swappable.hpp * Add ranges::make_heap * Add pop_heap * Add ranges::sort_heap * Update debug_assert.hpp * Update equal_to.hpp * Update cxx20_rel_ops.hpp * Add ranges::sort * Add saturate_cast * Add ranges::contains, ranges::contains_subrange * Update zip_view.hpp * Update saturate_cast.hpp * Update saturate_cast.hpp * Update counted_iterator.hpp * Update take_view.hpp * Add missing comparison operators * Fix ssize * Update from_range.hpp * Update string_view.hpp * Update emscripten from 3.1.34 -> 3.1.57 * Update from_range.hpp * Update from_range.hpp * Update expected.hpp * Add logging with custom tag * Add cmp_xxx * Add is_character * Update cmp.hpp * Add in_range * Add ranges::clamp * Update cmp.hpp * Update in_range.hpp * Update filter_view.hpp * Fix filter_view::iterator::iterator_category * Fix elements_view::iterator::iterator_category * Fix join_view::iterator::iterator_category * Add tuple_for_each_index * fix cmp_xxx * Add copy_template * Add sequence_for_each * Add bind * Add test * Update string_view.hpp * Update docs * Update version_history.txt * Update version_history.txt * Add missing groups * Update mainpage.txt * Update header.html --- .github/workflows/test-emscripten.yml | 2 +- Doxyfile | 2 +- .../doxygen-custom/header.html | 4 +- docs/mainpage.txt | 10 +- docs/pages/version_history.txt | 105 ++++ .../log/include/vccc/__log/detail/buffer.h | 8 +- .../log/include/vccc/__log/detail/log_impl.h | 11 +- include/log/include/vccc/__log/logger.hpp | 59 +- include/vccc/__algorithm/ranges/clamp.hpp | 66 +++ include/vccc/__algorithm/ranges/contains.hpp | 66 +++ .../__algorithm/ranges/contains_subrange.hpp | 73 +++ include/vccc/__algorithm/ranges/find_end.hpp | 82 +++ .../vccc/__algorithm/ranges/find_first_of.hpp | 76 +++ include/vccc/__algorithm/ranges/find_last.hpp | 141 +++++ include/vccc/__algorithm/ranges/fold_left.hpp | 2 +- .../vccc/__algorithm/ranges/in_fun_result.hpp | 5 + include/vccc/__algorithm/ranges/make_heap.hpp | 72 +++ include/vccc/__algorithm/ranges/pop_heap.hpp | 71 +++ include/vccc/__algorithm/ranges/sort.hpp | 72 +++ include/vccc/__algorithm/ranges/sort_heap.hpp | 66 +++ include/vccc/__array/to_array.hpp | 45 ++ .../vccc/__compare/three_way_comparable.hpp | 28 + include/vccc/__concepts/swap.hpp | 3 +- include/vccc/__concepts/value_swappable.hpp | 5 + include/vccc/__core/byte.hpp | 5 + include/vccc/__core/debug_assert.hpp | 22 + .../__core/ignore_dumb_diagnostics_pop.hpp | 14 + .../__core/ignore_dumb_diagnostics_push.hpp | 17 + .../vccc/__expected/bad_expected_access.hpp | 5 + include/vccc/__expected/expected.hpp | 13 +- include/vccc/__expected/unexpect.hpp | 5 + include/vccc/__expected/unexpected.hpp | 5 + include/vccc/__functional/bind_back.hpp | 68 +++ include/vccc/__functional/bind_front.hpp | 66 +++ .../vccc/__functional/detail/bind_base.hpp | 76 +++ include/vccc/__functional/equal_to.hpp | 1 - include/vccc/__iterator/advance.hpp | 5 +- .../vccc/__iterator/basic_const_iterator.hpp | 6 +- include/vccc/__iterator/common_iterator.hpp | 27 + include/vccc/__iterator/counted_iterator.hpp | 17 +- .../__iterator/detail/iter_exchange_move.hpp | 28 + .../vccc/__iterator/detail/iter_move_std.hpp | 42 -- .../vccc/__iterator/indirectly_swappable.hpp | 2 +- include/vccc/__iterator/iter_move.hpp | 115 ++-- include/vccc/__iterator/iter_swap.hpp | 25 +- include/vccc/__iterator/move_iterator.hpp | 109 ++++ include/vccc/__iterator/next.hpp | 5 +- include/vccc/__iterator/prev.hpp | 5 +- include/vccc/__iterator/projected.hpp | 3 + include/vccc/__iterator/reverse_iterator.hpp | 102 ++++ include/vccc/__memory/destroy.hpp | 4 + include/vccc/__memory/to_address.hpp | 5 + include/vccc/__numeric/saturate_cast.hpp | 73 +++ include/vccc/__ranges/as_const_pointer.hpp | 5 + include/vccc/__ranges/begin.hpp | 5 +- include/vccc/__ranges/cbegin.hpp | 5 +- include/vccc/__ranges/cdata.hpp | 5 +- include/vccc/__ranges/cend.hpp | 5 +- include/vccc/__ranges/crbegin.hpp | 5 +- include/vccc/__ranges/crend.hpp | 5 +- include/vccc/__ranges/data.hpp | 5 +- include/vccc/__ranges/distance.hpp | 5 +- include/vccc/__ranges/empty.hpp | 5 +- include/vccc/__ranges/end.hpp | 5 +- include/vccc/__ranges/from_range.hpp | 6 +- .../vccc/__ranges/non_propagating_cache.hpp | 8 +- include/vccc/__ranges/output_range.hpp | 5 + .../vccc/__ranges/possibly_const_range.hpp | 5 + include/vccc/__ranges/range_adaptor.hpp | 5 + include/vccc/__ranges/rbegin.hpp | 5 +- include/vccc/__ranges/rend.hpp | 5 +- include/vccc/__ranges/simple_view.hpp | 5 + include/vccc/__ranges/size.hpp | 5 +- include/vccc/__ranges/ssize.hpp | 5 +- include/vccc/__ranges/subrange.hpp | 7 +- include/vccc/__ranges/views/all.hpp | 5 +- .../__ranges/views/cartesian_product_view.hpp | 41 +- include/vccc/__ranges/views/drop_view.hpp | 5 + include/vccc/__ranges/views/elements_view.hpp | 25 +- .../vccc/__ranges/views/enumerate_view.hpp | 22 +- include/vccc/__ranges/views/filter_view.hpp | 40 +- include/vccc/__ranges/views/join_view.hpp | 67 ++- .../vccc/__ranges/views/join_with_view.hpp | 23 +- include/vccc/__ranges/views/single.hpp | 6 +- include/vccc/__ranges/views/take_view.hpp | 34 +- .../vccc/__ranges/views/transform_view.hpp | 39 +- include/vccc/__ranges/views/views.hpp | 4 + include/vccc/__ranges/views/zip.hpp | 50 ++ include/vccc/__ranges/views/zip_transform.hpp | 66 +++ .../__ranges/views/zip_transform_view.hpp | 419 +++++++++++++ include/vccc/__ranges/views/zip_view.hpp | 558 ++++++++++++++++++ include/vccc/__span/dynamic_extent.hpp | 5 + include/vccc/__tuple/tuple_for_each.hpp | 99 ++++ include/vccc/__tuple/tuple_transform.hpp | 18 +- include/vccc/__type_traits/copy_template.hpp | 30 + include/vccc/__type_traits/core/size.hpp | 6 +- .../vccc/__type_traits/has_operator_arrow.hpp | 5 + .../has_typename_difference_type.hpp | 5 + .../has_typename_element_type.hpp | 5 + .../vccc/__type_traits/has_typename_type.hpp | 5 + .../__type_traits/has_typename_value_type.hpp | 5 + include/vccc/__type_traits/is_character.hpp | 50 ++ include/vccc/__type_traits/is_complete.hpp | 5 + include/vccc/__type_traits/is_range.hpp | 6 +- .../vccc/__type_traits/is_referenceable.hpp | 5 + include/vccc/__type_traits/is_swappable.hpp | 5 + include/vccc/__type_traits/is_tuple_like.hpp | 6 + include/vccc/__type_traits/iterable.hpp | 3 +- include/vccc/__type_traits/maybe_const.hpp | 5 + .../__type_traits/simple_common_reference.hpp | 5 + include/vccc/__utility/cmp.hpp | 99 ++++ include/vccc/__utility/cxx20_rel_ops.hpp | 5 + include/vccc/__utility/in_range.hpp | 27 + include/vccc/__utility/sequence_for_each.hpp | 62 ++ include/vccc/__variant/holds_alternative.hpp | 5 + include/vccc/algorithm.hpp | 12 +- include/vccc/array.hpp | 12 + include/vccc/expected.hpp | 2 + include/vccc/functional.hpp | 2 + include/vccc/iterator.hpp | 3 +- include/vccc/memory.hpp | 2 + include/vccc/numeric.hpp | 5 +- include/vccc/string_view.hpp | 3 +- include/vccc/tuple.hpp | 1 + include/vccc/type_traits.hpp | 2 + include/vccc/utility.hpp | 3 + test/algorithm_test.cpp | 198 +++++++ test/functional_test.cpp | 38 ++ test/iterator_test.cpp | 50 +- test/log_test.cpp | 10 +- test/ranges_test.cpp | 67 +++ test/type_traits_test.cpp | 6 + 132 files changed, 4031 insertions(+), 320 deletions(-) create mode 100644 include/vccc/__algorithm/ranges/clamp.hpp create mode 100644 include/vccc/__algorithm/ranges/contains.hpp create mode 100644 include/vccc/__algorithm/ranges/contains_subrange.hpp create mode 100644 include/vccc/__algorithm/ranges/find_end.hpp create mode 100644 include/vccc/__algorithm/ranges/find_first_of.hpp create mode 100644 include/vccc/__algorithm/ranges/find_last.hpp create mode 100644 include/vccc/__algorithm/ranges/make_heap.hpp create mode 100644 include/vccc/__algorithm/ranges/pop_heap.hpp create mode 100644 include/vccc/__algorithm/ranges/sort.hpp create mode 100644 include/vccc/__algorithm/ranges/sort_heap.hpp create mode 100644 include/vccc/__array/to_array.hpp create mode 100644 include/vccc/__compare/three_way_comparable.hpp create mode 100644 include/vccc/__core/debug_assert.hpp create mode 100644 include/vccc/__core/ignore_dumb_diagnostics_pop.hpp create mode 100644 include/vccc/__core/ignore_dumb_diagnostics_push.hpp create mode 100644 include/vccc/__functional/bind_back.hpp create mode 100644 include/vccc/__functional/bind_front.hpp create mode 100644 include/vccc/__functional/detail/bind_base.hpp create mode 100644 include/vccc/__iterator/detail/iter_exchange_move.hpp delete mode 100644 include/vccc/__iterator/detail/iter_move_std.hpp create mode 100644 include/vccc/__iterator/move_iterator.hpp create mode 100644 include/vccc/__iterator/reverse_iterator.hpp create mode 100644 include/vccc/__numeric/saturate_cast.hpp create mode 100644 include/vccc/__ranges/views/zip.hpp create mode 100644 include/vccc/__ranges/views/zip_transform.hpp create mode 100644 include/vccc/__ranges/views/zip_transform_view.hpp create mode 100644 include/vccc/__ranges/views/zip_view.hpp create mode 100644 include/vccc/__tuple/tuple_for_each.hpp create mode 100644 include/vccc/__type_traits/copy_template.hpp create mode 100644 include/vccc/__type_traits/is_character.hpp create mode 100644 include/vccc/__utility/cmp.hpp create mode 100644 include/vccc/__utility/in_range.hpp create mode 100644 include/vccc/__utility/sequence_for_each.hpp create mode 100644 include/vccc/array.hpp diff --git a/.github/workflows/test-emscripten.yml b/.github/workflows/test-emscripten.yml index d017aad0..f5074a2f 100644 --- a/.github/workflows/test-emscripten.yml +++ b/.github/workflows/test-emscripten.yml @@ -8,7 +8,7 @@ on: env: BUILD_TYPE: Release - EMSDK_VERSION: 3.1.34 + EMSDK_VERSION: 3.1.57 jobs: build: diff --git a/Doxyfile b/Doxyfile index 31021379..6fb0c444 100644 --- a/Doxyfile +++ b/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = VCCC # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.1 +PROJECT_NUMBER = 2024.05 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/docs/doxygen-awesome-css/doxygen-custom/header.html b/docs/doxygen-awesome-css/doxygen-custom/header.html index 6fbde5b4..efad961e 100644 --- a/docs/doxygen-awesome-css/doxygen-custom/header.html +++ b/docs/doxygen-awesome-css/doxygen-custom/header.html @@ -7,7 +7,7 @@ - + @@ -15,7 +15,7 @@ - + diff --git a/docs/mainpage.txt b/docs/mainpage.txt index 4140846a..7d03c4d6 100644 --- a/docs/mainpage.txt +++ b/docs/mainpage.txt @@ -5,21 +5,26 @@ \section Overview VCCC is a cross-platform header-only library consisting of several modules written C++14.
-It provides various algorithms, implementing C++17 and C++20 feature in C++14. +It provides various algorithms, implementing C++17 ... C++26 feature in C++14. \section compiler_support Compiler Support - GCC 6.0 or above - Clang 8.0 or above - MSVC 15.0 or above -- Emscripten 2.0.14 or above (below versions are not tested) +- Emscripten 3.1.57 or above (tested 2.0.14 ~) \section Libraries +- \subpage algorithm. \copybrief algorithm +- \subpage array. \copybrief array +- \subpage compare. \copybrief compare - \subpage concepts. \copybrief concepts +- \subpage expected. \copybrief expected - \subpage functional. \copybrief functional - \subpage iterator. \copybrief iterator - \subpage literal. \copybrief literal - \subpage log. \copybrief log - \subpage math. \copybrief math +- \subpage memory. \copybrief memory - \subpage numeric. \copybrief numeric - \subpage optional. \copybrief optional - \subpage random. \copybrief random @@ -31,6 +36,7 @@ It provides various algorithms, implementing C++17 and C++20 feature in C++14. - \subpage type_support. \copybrief type_support - \subpage type_traits. \copybrief type_traits - \subpage utility. \copybrief utility +- \subpage variant. \copybrief variant \section third_party_libraries Third Party Libraries \subsection boost_predef Boost.Predef diff --git a/docs/pages/version_history.txt b/docs/pages/version_history.txt index b20063de..538090ad 100644 --- a/docs/pages/version_history.txt +++ b/docs/pages/version_history.txt @@ -3,6 +3,111 @@ \tableofcontents +\section version_2024_05 v2024.05 +- \subpage log + - Add \ref Log_t::operator() for custom priority and tag + +- \subpage algorithm + - Add \ref ranges::clamp + - Add \ref ranges::contains + - Add \ref ranges::constains_subrange + - Add \ref ranges::find_end + - Add \ref ranges::find_first_of + - Add \ref ranges::find_last + - Add \ref ranges::make_heap + - Add \ref ranges::pop_heap + - Add \ref ranges::sort + - Add \ref ranges::sort_heap + - Fix \ref ranges::fold_left + +- \subpage array + - Add \ref to_array + +- \subpage compare + - Add \ref unstable_three_way_comparable + +- \subpage concepts + - Fix lookup of \ref ranges::swap + +- \subpage expected + - Fix \ref expected::operator*() + +- \subpage functional + - Add \ref bind_back + - Add \ref bind_front + - Fix \ref ranges::equal_to + +- \subpage iterator + - Add \ref common_iterator::iter_move + - Add \ref common_iterator::iter_swap + - Add \ref counted_iterator::iter_move + - Add \ref counted_iterator::iter_swap + - Add \ref move_iterator + - Add \ref reverse_iterator + - Fix lookup of \ref ranges::advance + - Fix comparison with \ref counted_iterator and \ref default_sentinel_t + - Fix \ref indirectly_swappable + - Fix \ref ranges::iter_move + - Fix \ref ranges::iter_swap + - Fix lookup of \ref ranges::next + - Fix lookup of \ref ranges::prev + +- \subpage numeric + - Add \ref saturate_cast + +- \subpage ranges + - Add \ref ranges::cartesian_product_view::iter_move + - Add \ref ranges::cartesian_product_view::iter_swap + - Add \ref ranges::enumerate_view::iter_move + - Add \ref ranges::enumerate_view::iter_swap + - Add \ref ranges::filter_view::iter_move + - Add \ref ranges::filter_view::iter_swap + - Add \ref ranges::join_view::iter_move + - Add \ref ranges::join_view::iter_swap + - Add \ref ranges::join_with_view::iter_move + - Add \ref ranges::join_with_view::iter_swap + - Add \ref ranges::transform_view::iter_move + - Add \ref ranges::zip_view, \ref views::zip + - Add \ref ranges::zip_transform_view, \ref views::zip_transform + - Fix lookup of \ref ranges::begin + - Fix lookup of \ref ranges::cbegin + - Fix lookup of \ref ranges::cdata + - Fix lookup of \ref ranges::cend + - Fix lookup of \ref ranges::crbegin + - Fix lookup of \ref ranges::crend + - Fix lookup of \ref ranges::data + - Fix lookup of \ref ranges::distance + - Fix lookup of \ref ranges::empty + - Fix lookup of \ref ranges::end + - Fix lookup of \ref ranges::from_range + - Fix \ref ranges::non_propagating_cache::non_propagating_cache() + - Fix lookup of \ref ranges::rbegin + - Fix lookup of \ref ranges::rend + - Fix lookup of \ref ranges::size + - Fix lookup of \ref ranges::ssize + - Fix initialization order of \ref ranges::subrange + - Fix lookup of \ref views::all + - Fix lookup of \ref views::single + - Fix comparison with \ref take_view::sentinel and \ref counted_iterator + - Fix comparison with \ref transform_view::iterator and \ref transform_view::sentinel + +- \subpage tuple + - Add \ref tuple_for_each, \ref tuple_for_each_index + - Fix \ref tuple_transform + +- \subpage type_traits + - Add \ref copy_template, \ref copy_template_t + - Fix \ref ssize + +- \subpage utility + - Add \ref cmp_equal, \ref cmp_not_equal, \ref cmp_less, \ref cmp_greater, \ref cmp_less_equal, \ref cmp_greater_equal + - Add \ref in_range + - Add \ref sequence_for_each + +- Others + - Remove false diagnostic messages + - Update emscripten from 3.1.34 -> 3.1.57 + \section version_1_3_1 v1.3.1 - \subpage algorithm - Add \ref vccc::ranges::copy diff --git a/include/log/include/vccc/__log/detail/buffer.h b/include/log/include/vccc/__log/detail/buffer.h index 764b8a89..9c1a9eb8 100644 --- a/include/log/include/vccc/__log/detail/buffer.h +++ b/include/log/include/vccc/__log/detail/buffer.h @@ -13,6 +13,8 @@ # include # # define VCCC_LOG_PRINTER(buf, tag, fmt, ...) __android_log_print(buf, tag, fmt, __VA_ARGS__) +# +# // https://developer.android.com/ndk/reference/group/logging # define VCCC_LOG_BUFFER_DEBUG ANDROID_LOG_DEBUG # define VCCC_LOG_BUFFER_INFO ANDROID_LOG_DEBUG # define VCCC_LOG_BUFFER_WARN ANDROID_LOG_ERROR @@ -22,7 +24,9 @@ # include "TargetConditionals.h" # include # -# define VCCC_LOG_PRINTER(buf, tag, fmt, ...) syslog(buf, tag fmt, __VA_ARGS__) +# define VCCC_LOG_PRINTER(buf, tag, fmt, ...) syslog(buf, "%s" fmt, tag, __VA_ARGS__) +# +# // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/syslog.3.html # define VCCC_LOG_BUFFER_DEBUG LOG_DEBUG # define VCCC_LOG_BUFFER_INFO LOG_DEBUG # define VCCC_LOG_BUFFER_WARN LOG_ERR @@ -31,7 +35,7 @@ # else // for wasm, Windows, MacOS # include # -# define VCCC_LOG_PRINTER(buf, tag, fmt, ...) VCCC_LOG_EXPAND(std::fprintf(buf, tag fmt "\n", __VA_ARGS__)) +# define VCCC_LOG_PRINTER(buf, tag, fmt, ...) VCCC_LOG_EXPAND(std::fprintf(buf, "%s" fmt "\n", tag, __VA_ARGS__)) # define VCCC_LOG_BUFFER_DEBUG stdout # define VCCC_LOG_BUFFER_INFO stdout # define VCCC_LOG_BUFFER_WARN stderr diff --git a/include/log/include/vccc/__log/detail/log_impl.h b/include/log/include/vccc/__log/detail/log_impl.h index 33f3813e..97ae6a94 100644 --- a/include/log/include/vccc/__log/detail/log_impl.h +++ b/include/log/include/vccc/__log/detail/log_impl.h @@ -6,16 +6,15 @@ # define VCCC_LOG_DETAIL_LOG_IMPL_H_ # # include "vccc/__log/detail/buffer.h" -# include "vccc/__log/detail/tag.h" # # ifdef NDEBUG -# define LOGD_IMPL(...) +# define LOGD_IMPL(tag, fmt, ...) # else -# define LOGD_IMPL(...) VCCC_LOG_EXPAND(VCCC_LOG_PRINTER(VCCC_LOG_BUFFER_DEBUG, VCCC_LOG_TAG_DEBUG, __VA_ARGS__)) +# define LOGD_IMPL(tag, fmt, ...) VCCC_LOG_EXPAND(VCCC_LOG_PRINTER(VCCC_LOG_BUFFER_DEBUG, tag, fmt, __VA_ARGS__)) # endif # -# define LOGI_IMPL(...) VCCC_LOG_EXPAND(VCCC_LOG_PRINTER(VCCC_LOG_BUFFER_INFO, VCCC_LOG_TAG_INFO, __VA_ARGS__)) -# define LOGW_IMPL(...) VCCC_LOG_EXPAND(VCCC_LOG_PRINTER(VCCC_LOG_BUFFER_WARN, VCCC_LOG_TAG_WARN, __VA_ARGS__)) -# define LOGE_IMPL(...) VCCC_LOG_EXPAND(VCCC_LOG_PRINTER(VCCC_LOG_BUFFER_ERROR, VCCC_LOG_TAG_ERROR, __VA_ARGS__)) +# define LOGI_IMPL(tag, fmt, ...) VCCC_LOG_EXPAND(VCCC_LOG_PRINTER(VCCC_LOG_BUFFER_INFO, tag, fmt, __VA_ARGS__)) +# define LOGW_IMPL(tag, fmt, ...) VCCC_LOG_EXPAND(VCCC_LOG_PRINTER(VCCC_LOG_BUFFER_WARN, tag, fmt, __VA_ARGS__)) +# define LOGE_IMPL(tag, fmt, ...) VCCC_LOG_EXPAND(VCCC_LOG_PRINTER(VCCC_LOG_BUFFER_ERROR, tag, fmt, __VA_ARGS__)) # # endif //VCCC_LOG_DETAIL_LOG_IMPL_H_ diff --git a/include/log/include/vccc/__log/logger.hpp b/include/log/include/vccc/__log/logger.hpp index ce97e293..aa8604cb 100644 --- a/include/log/include/vccc/__log/logger.hpp +++ b/include/log/include/vccc/__log/logger.hpp @@ -5,7 +5,9 @@ # ifndef VCCC_LOG_LOG_HPP # define VCCC_LOG_LOG_HPP # +# include "vccc/__core/inline_or_static.hpp" # include "vccc/__log/detail/log_impl.h" +# include "vccc/__log/detail/tag.h" # include "vccc/__log/stream_wrapper.hpp" @@ -51,19 +53,58 @@ if ostringstream& operator << is overloaded for user-defined types, it can be pr */ class Logger { public: + enum Priority { + kDebug, + kInfo, + kWarn, + kError, + }; + using stream_type = StreamWrapper; using string_type = std::string; constexpr Logger() = default; /** @brief Log output as debug */ - template void d(const Args&... args) const { d_(to_string(args...)); } + template void d(const Args&... args) const { + d_(VCCC_LOG_TAG_DEBUG, to_string(args...)); + } + /** @brief Informational log */ - template void i(const Args&... args) const { i_(to_string(args...)); } + template void i(const Args&... args) const { + i_(VCCC_LOG_TAG_INFO, to_string(args...)); + } + /** @brief Warning log */ - template void w(const Args&... args) const { w_(to_string(args...)); } + template void w(const Args&... args) const { + w_(VCCC_LOG_TAG_WARN, to_string(args...)); + } + /** @brief Error log */ - template void e(const Args&... args) const { e_(to_string(args...)); } + template void e(const Args&... args) const { + e_(VCCC_LOG_TAG_ERROR, to_string(args...)); + } + + template + void operator()(Priority priority, const char* tag, const Args&... args) const { + switch (priority) { + case kDebug: + this->d_(tag, to_string(args...)); + return; + + case kInfo: + this->i_(tag, to_string(args...)); + return; + + case kWarn: + this->w_(tag, to_string(args...)); + return; + + case kError: + this->e_(tag, to_string(args...)); + return; + } + } /** @brief Return logged value as std::string * @@ -86,16 +127,16 @@ class Logger { } private: - template void d_(const std::string& str) const { LOGD_IMPL("%s", str.c_str()); } - template void i_(const std::string& str) const { LOGI_IMPL("%s", str.c_str()); } - template void w_(const std::string& str) const { LOGW_IMPL("%s", str.c_str()); } - template void e_(const std::string& str) const { LOGE_IMPL("%s", str.c_str()); } + template void d_(const char* tag, const std::string& str) const { LOGD_IMPL(tag, "%s", str.c_str()); } + template void i_(const char* tag, const std::string& str) const { LOGI_IMPL(tag, "%s", str.c_str()); } + template void w_(const char* tag, const std::string& str) const { LOGW_IMPL(tag, "%s", str.c_str()); } + template void e_(const char* tag, const std::string& str) const { LOGE_IMPL(tag, "%s", str.c_str()); } }; /** @brief Global vccc::Logger instance for syntax sugar */ -constexpr Logger Log; +constexpr VCCC_INLINE_OR_STATIC Logger Log; /// @defgroup log_log_macro__macro__Logging_macros LOGD, LOGI, LOGID, LOGW, LOGWD, LOGE, LOGED /// @{ diff --git a/include/vccc/__algorithm/ranges/clamp.hpp b/include/vccc/__algorithm/ranges/clamp.hpp new file mode 100644 index 00000000..95f43b41 --- /dev/null +++ b/include/vccc/__algorithm/ranges/clamp.hpp @@ -0,0 +1,66 @@ +// +// Created by YongGyu Lee on 5/8/24. +// + +#ifndef VCCC_ALGORITHM_RANGES_CLAMP_HPP_ +#define VCCC_ALGORITHM_RANGES_CLAMP_HPP_ + +#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/projected.hpp" +#include "vccc/__type_traits/conjunction.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +struct clamp_niebloid { + template, + indirect_strict_weak_order> + >::value, int> = 0> + constexpr const T& operator()(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {}) const { + auto&& pv = vccc::invoke(proj, v); + + if (vccc::invoke(comp, std::forward(pv), vccc::invoke(proj, lo))) + return lo; + + if (vccc::invoke(comp, vccc::invoke(proj, hi), std::forward(pv))) + return hi; + + return v; + } +}; + +} // namespace detail + +/// @addtogroup algorithm +/// @{ + +/** +@brief clamps a value between a pair of boundary values + +If `v` compares less than `lo`, returns `lo`; otherwise if `hi` compares less than `v`, returns `hi`; otherwise returns `v`. + +The behavior is undefined if `lo` is greater than `hi`. + +

Complexity

+At most two comparisons and three applications of the projection. + +@sa [std::ranges::clamp](https://en.cppreference.com/w/cpp/algorithm/ranges/clamp) +@sa [std::clamp](https://en.cppreference.com/w/cpp/algorithm/clamp) +@sa vccc::clamp + */ +VCCC_INLINE_OR_STATIC constexpr detail::clamp_niebloid clamp{}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_ALGORITHM_RANGES_CLAMP_HPP_ diff --git a/include/vccc/__algorithm/ranges/contains.hpp b/include/vccc/__algorithm/ranges/contains.hpp new file mode 100644 index 00000000..c1976bde --- /dev/null +++ b/include/vccc/__algorithm/ranges/contains.hpp @@ -0,0 +1,66 @@ +// +// Created by YongGyu Lee on 4/15/24. +// + +#ifndef VCCC_ALGORITHM_RANGES_CONTAINS_HPP_ +#define VCCC_ALGORITHM_RANGES_CONTAINS_HPP_ + +#include +#include + +#include "vccc/__algorithm/ranges/find.hpp" +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__functional/equal_to.hpp" +#include "vccc/__functional/identity.hpp" +#include "vccc/__iterator/forward_iterator.hpp" +#include "vccc/__iterator/indirectly_comparable.hpp" +#include "vccc/__iterator/indirect_binary_predicate.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/__ranges/forward_range.hpp" +#include "vccc/__ranges/input_range.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__type_traits/conjunction.hpp" + +namespace vccc { +namespace ranges { + +/// @addtogroup algorithm +/// @{ + +namespace detail { + +struct contains_niebloid { + template, + sentinel_for, + projectable, + indirect_binary_predicate, const T*> + >::value, int> = 0> + constexpr bool operator()(I first, S last, const T& value, Proj proj = {}) const { + return ranges::find(std::move(first), last, value, proj) != last; + } + + template, + projectable, Proj>, + indirect_binary_predicate, Proj>, const T*> + >::value, int> = 0> + constexpr bool operator()(R&& r, const T& value, Proj proj = {}) const { + return (*this)(ranges::begin(r), ranges::end(r), std::move(value), proj); + } +}; + +} // namespace detail + +VCCC_INLINE_OR_STATIC constexpr detail::contains_niebloid contains{}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_ALGORITHM_RANGES_CONTAINS_HPP_ diff --git a/include/vccc/__algorithm/ranges/contains_subrange.hpp b/include/vccc/__algorithm/ranges/contains_subrange.hpp new file mode 100644 index 00000000..3556e180 --- /dev/null +++ b/include/vccc/__algorithm/ranges/contains_subrange.hpp @@ -0,0 +1,73 @@ +// +// Created by YongGyu Lee on 4/15/24. +// + +#ifndef VCCC_ALGORITHM_RANGES_CONTAINS_SUBRANGE_HPP_ +#define VCCC_ALGORITHM_RANGES_CONTAINS_SUBRANGE_HPP_ + +#include +#include + +#include "vccc/__algorithm/ranges/search.hpp" +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__functional/equal_to.hpp" +#include "vccc/__functional/identity.hpp" +#include "vccc/__iterator/forward_iterator.hpp" +#include "vccc/__iterator/indirectly_comparable.hpp" +#include "vccc/__iterator/indirect_binary_predicate.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/__ranges/forward_range.hpp" +#include "vccc/__ranges/input_range.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__type_traits/conjunction.hpp" + +namespace vccc { +namespace ranges { + +/// @addtogroup algorithm +/// @{ + +namespace detail { + +struct contains_subrange_niebloid { + template< + typename I1, typename S1, typename I2, typename S2, + typename Pred = ranges::equal_to, typename Proj1 = identity, typename Proj2 = identity, + std::enable_if_t, sentinel_for, + forward_iterator, sentinel_for, + indirectly_comparable + >::value, int> = 0> + constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { + return (first2 == last2) || + !ranges::search(first1, last1, first2, last2, pred, proj1, proj2).empty(); + } + + template< + typename R1, typename R2, + typename Pred = ranges::equal_to, typename Proj1 = identity, typename Proj2 = identity, + std::enable_if_t, + forward_range, + indirectly_comparable, iterator_t, Pred, Proj1, Proj2> + >::value, int> = 0> + constexpr bool operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { + return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), + std::move(pred), std::move(proj1), std::move(proj2)); + } +}; + +} // namespace detail + +VCCC_INLINE_OR_STATIC constexpr detail::contains_subrange_niebloid contains_subrange{}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_ALGORITHM_RANGES_CONTAINS_SUBRANGE_HPP_ diff --git a/include/vccc/__algorithm/ranges/find_end.hpp b/include/vccc/__algorithm/ranges/find_end.hpp new file mode 100644 index 00000000..c29fe00a --- /dev/null +++ b/include/vccc/__algorithm/ranges/find_end.hpp @@ -0,0 +1,82 @@ +// +// Created by YongGyu Lee on 4/12/24. +// + +#ifndef VCCC_ALGORITHM_RANGES_FIND_END_HPP_ +#define VCCC_ALGORITHM_RANGES_FIND_END_HPP_ + +#include +#include +#include + +#include "vccc/__algorithm/ranges/search.hpp" +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__functional/equal_to.hpp" +#include "vccc/__functional/identity.hpp" +#include "vccc/__iterator/forward_iterator.hpp" +#include "vccc/__iterator/indirectly_comparable.hpp" +#include "vccc/__iterator/next.hpp" +#include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/borrowed_subrange_t.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__ranges/subrange.hpp" +#include "vccc/__type_traits/conjunction.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +struct find_end_niebloid { + template, sentinel_for, + forward_iterator, sentinel_for, + indirectly_comparable + >::value, int> = 0> + constexpr subrange operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { + if (first2 == last2) { + auto last_it = ranges::next(first1, last1); + return {last_it, last_it}; + } + + auto result = ranges::search(std::move(first1),last1, first2, last2, pred, proj1, proj2); + if (result.empty()) + return result; + + for (;;) { + auto new_result = ranges::search(std::next(result.begin()), last1, first2, last2, pred, proj1, proj2); + if (new_result.empty()) + return result; + result = std::move(new_result); + } + } + + template, forward_range, + indirectly_comparable, iterator_t, Pred, Proj1, Proj2> + >::value, int> = 0> + constexpr borrowed_subrange_t operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { + return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), std::move(pred), std::move(proj1), std::move(proj2)); + } +}; + +} // namespace detail + +/// @addtogroup algorithm +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::find_end_niebloid find_end{}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_ALGORITHM_RANGES_FIND_END_HPP_ diff --git a/include/vccc/__algorithm/ranges/find_first_of.hpp b/include/vccc/__algorithm/ranges/find_first_of.hpp new file mode 100644 index 00000000..2cd35577 --- /dev/null +++ b/include/vccc/__algorithm/ranges/find_first_of.hpp @@ -0,0 +1,76 @@ +// +// Created by YongGyu Lee on 4/12/24. +// + +#ifndef VCCC_ALGORITHM_RANGES_FIND_FIRST_OF_HPP_ +#define VCCC_ALGORITHM_RANGES_FIND_FIRST_OF_HPP_ + +#include +#include + +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__iterator/indirectly_comparable.hpp" +#include "vccc/__iterator/input_iterator.hpp" +#include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__functional/equal_to.hpp" +#include "vccc/__functional/identity.hpp" +#include "vccc/__functional/invoke.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/borrowed_iterator_t.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/__type_traits/conjunction.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +struct find_first_of_niebloid { + template, sentinel_for, + forward_iterator, sentinel_for, + indirectly_comparable + >::value, int> = 0> + constexpr I1 operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { + for (; first1 != last1; ++first1) { + for (auto it = first2; it != last2; ++it) { + if (vccc::invoke(pred, vccc::invoke(proj1, *first1), vccc::invoke(proj2, *it))) { + return first1; + } + } + } + + return first1; + } + + template, forward_range, + indirectly_comparable, iterator_t, Pred, Proj1, Proj2> + >::value, int> = 0> + constexpr borrowed_iterator_t operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { + return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), std::move(pred), std::move(proj1), std::move(proj2)); + } +}; + +} // namespace detail + +/// @addtogroup algorithm +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::find_first_of_niebloid find_first_of{}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_ALGORITHM_RANGES_FIND_FIRST_OF_HPP_ diff --git a/include/vccc/__algorithm/ranges/find_last.hpp b/include/vccc/__algorithm/ranges/find_last.hpp new file mode 100644 index 00000000..0ff5635e --- /dev/null +++ b/include/vccc/__algorithm/ranges/find_last.hpp @@ -0,0 +1,141 @@ +// +// Created by YongGyu Lee on 4/11/24. +// + +#ifndef VCCC_ALGORITHM_RANGES_FIND_LAST_HPP_ +#define VCCC_ALGORITHM_RANGES_FIND_LAST_HPP_ + +#include +#include + +#include "vccc/__algorithm/ranges/detail/check_input.hpp" +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__iterator/forward_iterator.hpp" +#include "vccc/__iterator/indirect_binary_predicate.hpp" +#include "vccc/__iterator/indirect_unary_predicate.hpp" +#include "vccc/__iterator/next.hpp" +#include "vccc/__iterator/projected.hpp" +#include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__functional/equal_to.hpp" +#include "vccc/__functional/identity.hpp" +#include "vccc/__functional/invoke.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/borrowed_subrange_t.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/forward_range.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__ranges/subrange.hpp" +#include "vccc/__type_traits/conjunction.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +struct find_last_niebloid { + template, + sentinel_for, + projectable, + indirect_binary_predicate, const T*> + >::value, int> = 0> + constexpr subrange operator()(I first, S last, const T& value, Proj proj = {}) const { + I found{}; + + for (; first != last; ++first) { + if (vccc::invoke(proj, *first) == value) + found = first; + } + + if (found == I {}) + return {first, first}; + + return {found, ranges::next(found, last)}; + } + + template, + projectable, Proj>, + indirect_binary_predicate, Proj>, const T*> + >::value, int> = 0> + constexpr borrowed_subrange_t operator()(R&& r, const T& value, Proj proj = {}) const { + return (*this)(ranges::begin(r), ranges::end(r), value, std::ref(proj)); + } +}; + +struct find_last_if_niebloid { + template, + sentinel_for, + projectable, + indirect_unary_predicate> + >::value, int> = 0> + constexpr subrange operator()(I first, S last, Pred pred, Proj proj = {}) const { + I found{}; + for (; first != last; ++first) { + if (vccc::invoke(pred, vccc::invoke(proj, *first))) { + found = first; + } + } + + if (found == I {}) + return {first, first}; + + return {found, ranges::next(found, last)}; + } + + template, + projectable, Proj>, + indirect_unary_predicate, Proj>> + >::value, int> = 0> + constexpr borrowed_subrange_t operator()(R&& r, Pred pred, Proj proj = {}) const { + return (*this)(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); + } +}; + +struct find_last_if_not_niebloid { + template, + sentinel_for, + projectable, + indirect_unary_predicate> + >::value, int> = 0> + constexpr subrange operator()(I first, S last, Pred pred, Proj proj = {}) const { + I found{}; + for (; first != last; ++first) { + if (!vccc::invoke(pred, vccc::invoke(proj, *first))) { + found = first; + } + } + + if (found == I {}) + return {first, first}; + + return {found, ranges::next(found, last)}; + } + + template, + projectable, Proj>, + indirect_unary_predicate, Proj>> + >::value, int> = 0> + constexpr borrowed_subrange_t operator()(R&& r, Pred pred, Proj proj = {}) const { + return (*this)(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); + } +}; + +} // namespace detail + +/// @addtogroup algorithm +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::find_last_niebloid find_last{}; +VCCC_INLINE_OR_STATIC constexpr detail::find_last_if_niebloid find_last_if{}; +VCCC_INLINE_OR_STATIC constexpr detail::find_last_if_not_niebloid find_last_if_not{}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_ALGORITHM_RANGES_FIND_LAST_HPP_ diff --git a/include/vccc/__algorithm/ranges/fold_left.hpp b/include/vccc/__algorithm/ranges/fold_left.hpp index 10fba1c6..bba33b15 100644 --- a/include/vccc/__algorithm/ranges/fold_left.hpp +++ b/include/vccc/__algorithm/ranges/fold_left.hpp @@ -90,7 +90,7 @@ struct fold_left_niebloid { accum = vccc::invoke(f, std::move(accum), *first); } - return std::move(accum); + return accum; } template::value, int> = 0> diff --git a/include/vccc/__algorithm/ranges/in_fun_result.hpp b/include/vccc/__algorithm/ranges/in_fun_result.hpp index d0ba84e9..2e3d9051 100644 --- a/include/vccc/__algorithm/ranges/in_fun_result.hpp +++ b/include/vccc/__algorithm/ranges/in_fun_result.hpp @@ -15,6 +15,9 @@ namespace vccc { namespace ranges { +/// @addtogroup algorithm +/// @{ + template struct in_fun_result { VCCC_NO_UNIQUE_ADDRESS I in; @@ -37,6 +40,8 @@ struct in_fun_result { } }; +/// @} + } // namespace ranges } // namespace vccc diff --git a/include/vccc/__algorithm/ranges/make_heap.hpp b/include/vccc/__algorithm/ranges/make_heap.hpp new file mode 100644 index 00000000..9d680070 --- /dev/null +++ b/include/vccc/__algorithm/ranges/make_heap.hpp @@ -0,0 +1,72 @@ +// +// Created by YongGyu Lee on 4/15/24. +// + +#ifndef VCCC_ALGORITHM_RANGES_MAKE_HEAP_HPP_ +#define VCCC_ALGORITHM_RANGES_MAKE_HEAP_HPP_ + +#include +#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/next.hpp" +#include "vccc/__iterator/random_access_iterator.hpp" +#include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__iterator/sortable.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/borrowed_iterator_t.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/is_invocable.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +struct make_heap_niebloid { + public: + template, + sentinel_for, + sortable + >::value, int> = 0> + constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const { + auto last_iter = ranges::next(first, last); + + std::make_heap(std::move(first), last_iter, [&comp, &proj](auto&& lhs, auto&& rhs) { + return vccc::invoke( + comp, + vccc::invoke(proj, std::forward(lhs)), + vccc::invoke(proj, std::forward(rhs)) + ); + }); + return last_iter; + } + + template, + sortable, Comp, Proj> + >::value, int> = 0> + constexpr iterator_t operator()(R&& r, Comp comp = {}, Proj proj = {}) const { + return (*this)(ranges::begin(r), ranges::end(r), comp, proj); + } +}; + +} // namespace detail + +/// @addtogroup algorithm +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::make_heap_niebloid make_heap{}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_ALGORITHM_RANGES_MAKE_HEAP_HPP_ diff --git a/include/vccc/__algorithm/ranges/pop_heap.hpp b/include/vccc/__algorithm/ranges/pop_heap.hpp new file mode 100644 index 00000000..ad6b8f38 --- /dev/null +++ b/include/vccc/__algorithm/ranges/pop_heap.hpp @@ -0,0 +1,71 @@ +// +// Created by YongGyu Lee on 4/15/24. +// + +#ifndef VCCC_ALGORITHM_RANGES_POP_HEAP_HPP_ +#define VCCC_ALGORITHM_RANGES_POP_HEAP_HPP_ + +#include +#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/next.hpp" +#include "vccc/__iterator/random_access_iterator.hpp" +#include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__iterator/sortable.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/borrowed_iterator_t.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__ranges/random_access_range.hpp" +#include "vccc/__type_traits/conjunction.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +struct pop_heap_niebloid { + template, + sentinel_for, + sortable + >::value, int> = 0> + constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const { + auto last_iter = ranges::next(first, last); + + std::pop_heap(std::move(first), last_iter, [&](auto&& lhs, auto&& rhs) { + return vccc::invoke( + comp, + vccc::invoke(proj, std::forward(lhs)), + vccc::invoke(proj, std::forward(rhs)) + ); + }); + return last_iter; + } + + template, + sortable, Comp, Proj> + >::value, int> = 0> + constexpr borrowed_iterator_t operator()(R&& r, Comp comp = {}, Proj proj = {}) const { + return (*this)(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj)); + } +}; + +} // namespace detail + +/// @addtogroup algorithm +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::pop_heap_niebloid pop_heap{}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_ALGORITHM_RANGES_POP_HEAP_HPP_ diff --git a/include/vccc/__algorithm/ranges/sort.hpp b/include/vccc/__algorithm/ranges/sort.hpp new file mode 100644 index 00000000..782b352d --- /dev/null +++ b/include/vccc/__algorithm/ranges/sort.hpp @@ -0,0 +1,72 @@ +// +// Created by YongGyu Lee on 4/15/24. +// + +#ifndef VCCC_ALGORITHM_RANGES_SORT_HPP_ +#define VCCC_ALGORITHM_RANGES_SORT_HPP_ + +#include +#include +#include +#include + +#include "vccc/__algorithm/ranges/make_heap.hpp" +#include "vccc/__algorithm/ranges/sort_heap.hpp" +#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/next.hpp" +#include "vccc/__iterator/random_access_iterator.hpp" +#include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__iterator/sortable.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/borrowed_iterator_t.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__ranges/random_access_range.hpp" +#include "vccc/__type_traits/conjunction.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +struct sort_niebloid { + template, + sentinel_for, + sortable + >::value, int> = 0> + constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const { + if (first == last) + return first; + + auto last_iter = ranges::next(first, last); + ranges::make_heap(first, last_iter, std::ref(comp), std::ref(proj)); + ranges::sort_heap(first, last_iter, std::ref(comp), std::ref(proj)); + + return last_iter; + } + + template, + sortable, Comp, Proj> + >::value, int> = 0> + constexpr borrowed_iterator_t operator()(R&& r, Comp comp = {}, Proj proj = {}) const { + return (*this)(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj)); + } +}; + +} // namespace detail + +/// @addtogroup algorithm +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::sort_niebloid sort{}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_ALGORITHM_RANGES_SORT_HPP_ diff --git a/include/vccc/__algorithm/ranges/sort_heap.hpp b/include/vccc/__algorithm/ranges/sort_heap.hpp new file mode 100644 index 00000000..aebe59fd --- /dev/null +++ b/include/vccc/__algorithm/ranges/sort_heap.hpp @@ -0,0 +1,66 @@ +// +// Created by YongGyu Lee on 4/15/24. +// + +#ifndef VCCC_ALGORITHM_RANGES_SORT_HEAP_HPP_ +#define VCCC_ALGORITHM_RANGES_SORT_HEAP_HPP_ + +#include +#include +#include + +#include "vccc/__algorithm/ranges/pop_heap.hpp" +#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/next.hpp" +#include "vccc/__iterator/random_access_iterator.hpp" +#include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__iterator/sortable.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/borrowed_iterator_t.hpp" +#include "vccc/__ranges/end.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__ranges/random_access_range.hpp" +#include "vccc/__type_traits/conjunction.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +struct sort_heap_niebloid { + template, + sentinel_for, + sortable + >::value, int> = 0> + constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const { + auto last_iter = ranges::next(first, last); + for (; !(first == last); --last) + ranges::pop_heap(first, last, comp, proj); + return last_iter; + } + + template, + sortable, Comp, Proj> + >::value, int> = 0> + constexpr borrowed_iterator_t operator()(R&& r, Comp comp = {}, Proj proj = {}) const { + return (*this)(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj)); + } +}; + +} // namespace detail + +/// @addtogroup algorithm +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::sort_heap_niebloid sort_heap{}; + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_ALGORITHM_RANGES_SORT_HEAP_HPP_ diff --git a/include/vccc/__array/to_array.hpp b/include/vccc/__array/to_array.hpp new file mode 100644 index 00000000..dad651a6 --- /dev/null +++ b/include/vccc/__array/to_array.hpp @@ -0,0 +1,45 @@ +// +// Created by YongGyu Lee on 4/11/24. +// + +#ifndef VCCC_ARRAY_TO_ARRAY_HPP_ +#define VCCC_ARRAY_TO_ARRAY_HPP_ + +#include +#include +#include +#include + +namespace vccc { +namespace detail { + +template +constexpr std::array, N> to_array_impl(T (&a)[N], std::index_sequence) { + return {{a[I]...}}; +} + +template +constexpr std::array, N> to_array_impl(T (&&a)[N], std::index_sequence) { + return {{std::move(a[I])...}}; +} + +} // namespace detail + +/// @addtogroup array +/// @{ + +template::value && !std::is_array::value, int> = 0> +constexpr std::array, N> to_array(T (&a)[N]) { + return vccc::detail::to_array_impl(a, std::make_index_sequence{}); +} + +template::value && !std::is_array::value, int> = 0> +constexpr std::array, N> to_array(T (&&a)[N]) { + return vccc::detail::to_array_impl(std::move(a), std::make_index_sequence{}); +} + +/// @} + +} // namespace vccc + +#endif // VCCC_ARRAY_TO_ARRAY_HPP_ diff --git a/include/vccc/__compare/three_way_comparable.hpp b/include/vccc/__compare/three_way_comparable.hpp new file mode 100644 index 00000000..32682703 --- /dev/null +++ b/include/vccc/__compare/three_way_comparable.hpp @@ -0,0 +1,28 @@ +// +// Created by YongGyu Lee on 4/11/24. +// + +#ifndef VCCC_COMPARE_THREE_WAY_COMPARABLE_HPP_ +#define VCCC_COMPARE_THREE_WAY_COMPARABLE_HPP_ + +#include "vccc/__concepts/partially_ordered_with.hpp" +#include "vccc/__concepts/weakly_equality_comparable_with.hpp" +#include "vccc/__type_traits/conjunction.hpp" + +namespace vccc { + +/// @addtogroup compare +/// @{ + +template +struct unstable_three_way_comparable + : conjunction< + weakly_equality_comparable_with, + partially_ordered_with + > {}; + +/// @} + +} // namespace vccc + +#endif // VCCC_COMPARE_THREE_WAY_COMPARABLE_HPP_ diff --git a/include/vccc/__concepts/swap.hpp b/include/vccc/__concepts/swap.hpp index dd51ec29..857f87c6 100644 --- a/include/vccc/__concepts/swap.hpp +++ b/include/vccc/__concepts/swap.hpp @@ -79,7 +79,7 @@ struct swap_niebloid { } // namespace detail_ranges_swap /// Niebloids -inline namespace niebloid { +namespace niebloid { /// @addtogroup concepts /// @{ @@ -101,6 +101,7 @@ VCCC_INLINE_OR_STATIC constexpr detail_ranges_swap::swap_niebloid swap{}; /// @} } // namespace niebloid +using namespace niebloid; namespace detail_ranges_swap { diff --git a/include/vccc/__concepts/value_swappable.hpp b/include/vccc/__concepts/value_swappable.hpp index ca0f96e7..0a31d918 100644 --- a/include/vccc/__concepts/value_swappable.hpp +++ b/include/vccc/__concepts/value_swappable.hpp @@ -22,9 +22,14 @@ struct ValueSwappableImpl } // namespace detail +/// @addtogroup concepts +/// @{ + template struct ValueSwappable : detail::ValueSwappableImpl {}; +/// @} + } // namespace vccc #endif // VCCC_CONCEPTS_VALUE_SWAPPABLE_HPP diff --git a/include/vccc/__core/byte.hpp b/include/vccc/__core/byte.hpp index 2a3cc55e..ab725287 100644 --- a/include/vccc/__core/byte.hpp +++ b/include/vccc/__core/byte.hpp @@ -14,6 +14,9 @@ namespace vccc { +/// @addtogroup core +/// @{ + // TODO: Use CheckCXXTypeExists #if __cplusplus < 201703L @@ -138,6 +141,8 @@ to_integer(byte b) noexcept { #endif +/// @} + } // namespace vccc #endif // VCCC_CORE_BYTE_HPP diff --git a/include/vccc/__core/debug_assert.hpp b/include/vccc/__core/debug_assert.hpp new file mode 100644 index 00000000..4f5fd163 --- /dev/null +++ b/include/vccc/__core/debug_assert.hpp @@ -0,0 +1,22 @@ +// +// Created by YongGyu Lee on 4/15/24. +// + +#ifndef VCCC_CORE_DEBUG_ASSERT_HPP_ +#define VCCC_CORE_DEBUG_ASSERT_HPP_ + +#include + +#define VCCC_LINE_LOCATION_IMPL2(file, line) \ + "file: " file ", line " # line + +#define VCCC_LINE_LOCATION_IMPL(file, line) \ + VCCC_LINE_LOCATION_IMPL2(file, line) + +#define VCCC_LINE_LOCATION \ + VCCC_LINE_LOCATION_IMPL(__FILE__, __LINE__) + +#define VCCC_DEBUG_ASSERT(expr) \ + assert(((void) "Assertion on " VCCC_LINE_LOCATION, expr)) + +#endif // VCCC_CORE_DEBUG_ASSERT_HPP_ diff --git a/include/vccc/__core/ignore_dumb_diagnostics_pop.hpp b/include/vccc/__core/ignore_dumb_diagnostics_pop.hpp new file mode 100644 index 00000000..18a9edda --- /dev/null +++ b/include/vccc/__core/ignore_dumb_diagnostics_pop.hpp @@ -0,0 +1,14 @@ +// +// Created by YongGyu Lee on 4/12/24. +// + +#ifndef VCCC_CORE_IGNORE_DUMB_DIAGNOSTICS_PUSH_HPP_ +#define VCCC_CORE_IGNORE_DUMB_DIAGNOSTICS_PUSH_HPP_ + +#ifdef __clang__ +#pragma clang diagnostic pop +#elif defined(_MSC_VER) +#pragma warning( pop ) +#endif + +#endif // VCCC_CORE_IGNORE_DUMB_DIAGNOSTICS_PUSH_HPP_ diff --git a/include/vccc/__core/ignore_dumb_diagnostics_push.hpp b/include/vccc/__core/ignore_dumb_diagnostics_push.hpp new file mode 100644 index 00000000..fe1ac05c --- /dev/null +++ b/include/vccc/__core/ignore_dumb_diagnostics_push.hpp @@ -0,0 +1,17 @@ +// +// Created by YongGyu Lee on 4/12/24. +// + +#ifndef VCCC_CORE_IGNORE_DUMB_DIAGNOSTICS_PUSH_HPP_ +#define VCCC_CORE_IGNORE_DUMB_DIAGNOSTICS_PUSH_HPP_ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundefined-internal" + +#elif defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 5046) +#endif + +#endif // VCCC_CORE_IGNORE_DUMB_DIAGNOSTICS_PUSH_HPP_ diff --git a/include/vccc/__expected/bad_expected_access.hpp b/include/vccc/__expected/bad_expected_access.hpp index 093bcc41..5e1126e2 100644 --- a/include/vccc/__expected/bad_expected_access.hpp +++ b/include/vccc/__expected/bad_expected_access.hpp @@ -10,6 +10,9 @@ namespace vccc { +/// @addtogroup expected +/// @{ + template class bad_expected_access; @@ -43,6 +46,8 @@ class bad_expected_access : public bad_expected_access { E error_; }; +/// @} + } // namespace vccc #endif // VCCC_EXPECTED_BAD_EXPECTED_ACCESS_HPP_ diff --git a/include/vccc/__expected/expected.hpp b/include/vccc/__expected/expected.hpp index cc659f20..b75376ba 100644 --- a/include/vccc/__expected/expected.hpp +++ b/include/vccc/__expected/expected.hpp @@ -33,6 +33,9 @@ namespace vccc { +/// @addtogroup expected +/// @{ + template class expected; @@ -697,7 +700,13 @@ class expected : private detail::expected_control_smf::value, int> = 0> - constexpr void operator*() const noexcept {} + constexpr void operator*() & noexcept {} + template::value, int> = 0> + constexpr void operator*() const& noexcept {} + template::value, int> = 0> + constexpr void operator*() && noexcept {} + template::value, int> = 0> + constexpr void operator*() const&& noexcept {} VCCC_NODISCARD bool has_value() const noexcept { return base::has_value(); @@ -1086,6 +1095,8 @@ class expected : private detail::expected_control_smf= 202302L using unexpect_t = std::unexpect_t; @@ -30,6 +33,8 @@ struct unexpect_t { VCCC_INLINE_OR_STATIC constexpr unexpect_t unexpect{}; +/// @} + #endif } // namespace vccc diff --git a/include/vccc/__expected/unexpected.hpp b/include/vccc/__expected/unexpected.hpp index 4c7db6ee..ac8e548f 100644 --- a/include/vccc/__expected/unexpected.hpp +++ b/include/vccc/__expected/unexpected.hpp @@ -18,6 +18,9 @@ namespace vccc { +/// @addtogroup expected +/// @{ + template class unexpected { public: @@ -95,6 +98,8 @@ unexpected(E) -> unexpected; #endif +/// @} + } // namespace vccc #endif // VCCC_EXPECTED_UNEXPECTED_HPP_ diff --git a/include/vccc/__functional/bind_back.hpp b/include/vccc/__functional/bind_back.hpp new file mode 100644 index 00000000..6b505f6a --- /dev/null +++ b/include/vccc/__functional/bind_back.hpp @@ -0,0 +1,68 @@ +#ifndef VCCC_FUNCTIONAL_BIND_BACK_HPP_ +#define VCCC_FUNCTIONAL_BIND_BACK_HPP_ + +#include +#include +#include + +#include "vccc/__functional/detail/bind_base.hpp" +#include "vccc/__functional/invoke.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/copy_cvref.hpp" +#include "vccc/__type_traits/is_invocable.hpp" + +namespace vccc { +namespace detail { + +template +class bind_back_object : public bind_object_base, F, Args...> { + using base = bind_object_base, F, Args...>; + friend base; + + template + struct bind_invoke_result + : invoke_result, U&&..., copy_cvref_t...> {}; + + template + struct bind_nothrow_invocable + : is_nothrow_invocable, U&&..., copy_cvref_t...> {}; + + template + static constexpr typename bind_invoke_result::type + call(Self&& self, std::index_sequence, U&&... args) noexcept(bind_nothrow_invocable::value) { + return vccc::invoke( + std::forward(self).func_, + std::forward(args)..., + std::get(std::forward(self).args_)... + ); + } + + public: + using base::base; + using base::operator(); +}; + +} // namespace detail + +/// @addtogroup functional +/// @{ + +template, F>, + std::is_move_constructible>, + std::is_constructible, Args>..., + std::is_move_constructible>... +>::value, int> = 0> +constexpr auto bind_back(F&& f, Args&&... args) { + return detail::bind_back_object, std::decay_t...>{ + detail::bind_object_ctor_tag{}, + std::forward(f), + std::forward(args)... + }; +} + +/// @} + +} // namespace vccc + +#endif // VCCC_FUNCTIONAL_BIND_BACK_HPP_ diff --git a/include/vccc/__functional/bind_front.hpp b/include/vccc/__functional/bind_front.hpp new file mode 100644 index 00000000..8a91f25b --- /dev/null +++ b/include/vccc/__functional/bind_front.hpp @@ -0,0 +1,66 @@ +#ifndef VCCC_FUNCTIONAL_BIND_FRONT_HPP_ +#define VCCC_FUNCTIONAL_BIND_FRONT_HPP_ + +#include +#include + +#include "vccc/__functional/invoke.hpp" +#include "vccc/__functional/detail/bind_base.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/is_invocable.hpp" + +namespace vccc { +namespace detail { + +template +class bind_front_object : public bind_object_base, F, Args...> { + using base = bind_object_base, F, Args...>; + friend base; + + template + struct bind_invoke_result + : invoke_result, copy_cvref_t..., U&&...> {}; + + template + struct bind_nothrow_invocable + : is_nothrow_invocable, copy_cvref_t..., U&&...> {}; + + template + static constexpr typename bind_invoke_result::type + call(Self&& self, std::index_sequence, U&&... args) noexcept(bind_nothrow_invocable::value) { + return vccc::invoke( + std::forward(self).func_, + std::get(std::forward(self).args_)..., + std::forward(args)... + ); + } + + public: + using base::base; + using base::operator(); +}; + +} // namespace detail + +/// @addtogroup functional +/// @{ + +template, F>, + std::is_move_constructible>, + std::is_constructible, Args>..., + std::is_move_constructible>... +>::value, int> = 0> +constexpr auto bind_front(F&& f, Args&&... args) { + return detail::bind_front_object, std::decay_t...>{ + detail::bind_object_ctor_tag{}, + std::forward(f), + std::forward(args)... + }; +} + +/// @} + +} // namespace vccc + +#endif // VCCC_FUNCTIONAL_BIND_FRONT_HPP_ diff --git a/include/vccc/__functional/detail/bind_base.hpp b/include/vccc/__functional/detail/bind_base.hpp new file mode 100644 index 00000000..5534d0f8 --- /dev/null +++ b/include/vccc/__functional/detail/bind_base.hpp @@ -0,0 +1,76 @@ +#ifndef VCCC_FUNCTIONAL_DETAIL_BIND_BASE_HPP_ +#define VCCC_FUNCTIONAL_DETAIL_BIND_BASE_HPP_ + +#include +#include + +#include "vccc/__functional/invoke.hpp" +#include "vccc/__type_traits/copy_cvref.hpp" + +namespace vccc { +namespace detail { + +struct bind_object_ctor_tag{}; + +template +class bind_object_base { + template + struct bind_invoke_result : Derived::template bind_invoke_result {}; + + template + struct bind_nothrow_invocable : Derived::template bind_nothrow_invocable {}; + + using index_sequence = std::index_sequence_for; + + public: + template + constexpr bind_object_base(bind_object_ctor_tag, F2&& func, Args2&&... args) + : func_(std::forward(func)) + , args_(std::forward(args)...) {} + + template + constexpr typename bind_invoke_result::type + operator()(U&&... args) & noexcept(bind_nothrow_invocable::value) { + return call(*this, std::forward(args)...); + return Derived::call(derived(), index_sequence{}, std::forward(args)...); + } + + template + constexpr typename bind_invoke_result::type + operator()(U&&... args) const & noexcept(bind_nothrow_invocable::value) { + return call(*this, std::forward(args)...); + } + + template + constexpr typename bind_invoke_result::type + operator()(U&&... args) && noexcept(bind_nothrow_invocable::value) { + return call(std::move(*this), std::forward(args)...); + } + + template + constexpr typename bind_invoke_result::type + operator()(U&&... args) const && noexcept(bind_nothrow_invocable::value) { + return call(std::move(*this), std::forward(args)...); + } + + protected: + F func_; + std::tuple args_; + + private: + template + static constexpr typename bind_invoke_result, U&&...>::type + call(Self&& self, U&&... args) noexcept(bind_nothrow_invocable, U&&...>::value) { + return Derived::call(std::forward(self).derived(), index_sequence{}, std::forward(args)...); + } + + Derived& derived() & { return static_cast(*this); } + const Derived& derived() const & { return static_cast(*this); } + Derived&& derived() && { return static_cast(*this); } + const Derived&& derived() const && { return static_cast(*this); } +}; + +} // namespace detail +} // namespace vccc + +#endif // VCCC_FUNCTIONAL_DETAIL_BIND_BASE_HPP_ diff --git a/include/vccc/__functional/equal_to.hpp b/include/vccc/__functional/equal_to.hpp index 8903abd9..804939ce 100644 --- a/include/vccc/__functional/equal_to.hpp +++ b/include/vccc/__functional/equal_to.hpp @@ -24,7 +24,6 @@ struct equal_to { constexpr bool operator()(T&& t, U&& u) const noexcept(noexcept(bool(std::forward(t) == std::forward(u)))) { - using namespace vccc::rel_ops; return std::forward(t) == std::forward(u); } }; diff --git a/include/vccc/__iterator/advance.hpp b/include/vccc/__iterator/advance.hpp index 83cdff39..8442dce2 100644 --- a/include/vccc/__iterator/advance.hpp +++ b/include/vccc/__iterator/advance.hpp @@ -147,7 +147,7 @@ struct advance_niebloid { }; } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup iterator /// @{ @@ -160,7 +160,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::advance_niebloid advance{}; /// @} /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; namespace detail { diff --git a/include/vccc/__iterator/basic_const_iterator.hpp b/include/vccc/__iterator/basic_const_iterator.hpp index 3a9df09f..ed382966 100644 --- a/include/vccc/__iterator/basic_const_iterator.hpp +++ b/include/vccc/__iterator/basic_const_iterator.hpp @@ -91,6 +91,9 @@ struct const_iterator_implicit_conversion_check } +/// @addtogroup iterator +/// @{ + template class basic_const_iterator : public detail::basic_const_iterator_category { using rvalue_reference = common_reference_t&&, iter_rvalue_reference_t>; @@ -414,8 +417,7 @@ template struct common_type, basic_const_iterator> : detail::basic_const_iterator_common_type {}; - - +/// @} } // namespace vccc diff --git a/include/vccc/__iterator/common_iterator.hpp b/include/vccc/__iterator/common_iterator.hpp index 2397b73d..3e7a03bd 100644 --- a/include/vccc/__iterator/common_iterator.hpp +++ b/include/vccc/__iterator/common_iterator.hpp @@ -21,7 +21,11 @@ #include "vccc/__iterator/forward_iterator.hpp" #include "vccc/__iterator/incrementable_traits.hpp" #include "vccc/__iterator/indirectly_readable.hpp" +#include "vccc/__iterator/indirectly_swappable.hpp" +#include "vccc/__iterator/input_iterator.hpp" #include "vccc/__iterator/input_or_output_iterator.hpp" +#include "vccc/__iterator/iter_move.hpp" +#include "vccc/__iterator/iter_swap.hpp" #include "vccc/__iterator/iterator_tag.hpp" #include "vccc/__iterator/iterator_traits/cxx20_iterator_traits.hpp" #include "vccc/__iterator/sentinel_for.hpp" @@ -37,6 +41,9 @@ namespace vccc { +/// @addtogroup iterator +/// @{ + template class common_iterator { class proxy { @@ -277,6 +284,24 @@ class common_iterator { } } + template, + input_iterator + >::value, int> = 0> + friend constexpr decltype(auto) iter_move(const common_iterator& i) + noexcept(noexcept(ranges::iter_move(std::declval()))) + { + return vccc::ranges::iter_move(i.iterator()); + } + + template + ::value, int> = 0> + friend constexpr void iter_swap(const common_iterator& x, const common_iterator& y) + noexcept(noexcept(ranges::iter_swap(std::declval(), std::declval()))) + { + ranges::iter_swap(x.iterator(), y.iterator()); + } + private: decltype(auto) iterator() { return detail::variant_raw_get(var_._base().storage(), in_place_index<0>); @@ -372,6 +397,8 @@ struct cxx20_iterator_traits> : detail::common_iterator_ca template struct detail::is_primary_iterator_traits< cxx20_iterator_traits> > : std::false_type {}; +/// @} + } // namespace vccc template diff --git a/include/vccc/__iterator/counted_iterator.hpp b/include/vccc/__iterator/counted_iterator.hpp index e9e1463c..3c00b893 100644 --- a/include/vccc/__iterator/counted_iterator.hpp +++ b/include/vccc/__iterator/counted_iterator.hpp @@ -10,6 +10,7 @@ #include #include "vccc/__core/constexpr.hpp" +#include "vccc/__core/debug_assert.hpp" #include "vccc/__concepts/assignable_from.hpp" #include "vccc/__concepts/common_with.hpp" #include "vccc/__concepts/convertible_to.hpp" @@ -20,11 +21,13 @@ #include "vccc/__iterator/default_sentinel_t.hpp" #include "vccc/__iterator/forward_iterator.hpp" #include "vccc/__iterator/indirectly_readable.hpp" +#include "vccc/__iterator/indirectly_swappable.hpp" #include "vccc/__iterator/input_iterator.hpp" #include "vccc/__iterator/input_or_output_iterator.hpp" #include "vccc/__iterator/iter_difference_t.hpp" #include "vccc/__iterator/iter_move.hpp" #include "vccc/__iterator/iter_rvalue_reference_t.hpp" +#include "vccc/__iterator/iter_swap.hpp" #include "vccc/__iterator/iter_value_t.hpp" #include "vccc/__iterator/random_access_iterator.hpp" #include "vccc/__memory/to_address.hpp" @@ -216,9 +219,15 @@ class counted_iterator friend constexpr bool operator==(const counted_iterator& x, default_sentinel_t) { return x.count() == 0; } + friend constexpr bool operator==(default_sentinel_t, const counted_iterator& x) { + return x.count() == 0; + } friend constexpr bool operator!=(const counted_iterator& x, default_sentinel_t) { return x.count() != 0; } + friend constexpr bool operator!=(default_sentinel_t, const counted_iterator& x) { + return x.count() != 0; + } template @@ -249,7 +258,13 @@ class counted_iterator return ranges::iter_move(i.base()); } - // TODO: implement iter_swap + template::value, int> = 0> + friend constexpr void iter_swap(const counted_iterator& x, const counted_iterator& y) + noexcept(noexcept(ranges::iter_swap(x.base(), y.base()))) + { + VCCC_DEBUG_ASSERT(x.count() != 0 && y.count() != 0); + ranges::iter_swap(x.base(), y.base()); + } private: iterator_type current_; diff --git a/include/vccc/__iterator/detail/iter_exchange_move.hpp b/include/vccc/__iterator/detail/iter_exchange_move.hpp new file mode 100644 index 00000000..1e3dbd68 --- /dev/null +++ b/include/vccc/__iterator/detail/iter_exchange_move.hpp @@ -0,0 +1,28 @@ +// +// Created by YongGyu Lee on 4/15/24. +// + +#ifndef VCCC_ITERATOR_DETAIL_ITER_EXCHANGE_MOVE_HPP_ +#define VCCC_ITERATOR_DETAIL_ITER_EXCHANGE_MOVE_HPP_ + +#include + +#include "vccc/__iterator/iter_move.hpp" +#include "vccc/__iterator/iter_value_t.hpp" + +namespace vccc { +namespace detail { + +template +constexpr iter_value_t> iter_exchange_move(T&& x, U&& y) + noexcept(noexcept(iter_value_t>(ranges::iter_move(x)))) +{ + iter_value_t> tmp(ranges::iter_move(x)); + *x = ranges::iter_move(y); + return tmp; +} + +} // namespace detail +} // namespace vccc + +#endif // VCCC_ITERATOR_DETAIL_ITER_EXCHANGE_MOVE_HPP_ diff --git a/include/vccc/__iterator/detail/iter_move_std.hpp b/include/vccc/__iterator/detail/iter_move_std.hpp deleted file mode 100644 index 1aec64b9..00000000 --- a/include/vccc/__iterator/detail/iter_move_std.hpp +++ /dev/null @@ -1,42 +0,0 @@ -// -// Created by yonggyulee on 2023/12/25. -// - -#ifndef VCCC_ITERATOR_DETAIL_ITER_MOVE_STD_HPP_ -#define VCCC_ITERATOR_DETAIL_ITER_MOVE_STD_HPP_ - -#if __cplusplus < 202002L - -#include -#include - -#include "vccc/__iterator/iter_move.hpp" -#include "vccc/__iterator/iter_rvalue_reference_t.hpp" - -namespace std { - -template -constexpr vccc::iter_rvalue_reference_t -iter_move(const reverse_iterator& i) - noexcept( - is_nothrow_copy_constructible::value && - noexcept(vccc::ranges::iter_move(--declval())) - ) -{ - auto tmp = i.base(); - return vccc::ranges::iter_move(--tmp); -} - -template -constexpr vccc::iter_rvalue_reference_t -iter_move(const move_iterator& i) - noexcept(noexcept(vccc::ranges::iter_move(--declval()))) -{ - return vccc::ranges::iter_move(i.base()); -} - -} // namespace std - -#endif - -#endif // VCCC_ITERATOR_DETAIL_ITER_MOVE_STD_HPP_ diff --git a/include/vccc/__iterator/indirectly_swappable.hpp b/include/vccc/__iterator/indirectly_swappable.hpp index 28965687..fddc7e80 100644 --- a/include/vccc/__iterator/indirectly_swappable.hpp +++ b/include/vccc/__iterator/indirectly_swappable.hpp @@ -19,7 +19,7 @@ template struct indirectly_swappable_test_iter_swap : std::false_type {}; template struct indirectly_swappable_test_iter_swap< - I1, I2, void_t(), std::declval()))>> : std::false_type {}; + I1, I2, void_t(), std::declval()))>> : std::true_type {}; template< typename I1, diff --git a/include/vccc/__iterator/iter_move.hpp b/include/vccc/__iterator/iter_move.hpp index 8559b2b2..b919d3ea 100644 --- a/include/vccc/__iterator/iter_move.hpp +++ b/include/vccc/__iterator/iter_move.hpp @@ -17,78 +17,68 @@ namespace vccc { namespace ranges { -namespace detail { +namespace detail_iter_move { -using vccc::detail::return_category; +struct iter_move_niebloid { + private: + template + using return_category = vccc::detail::return_category; + + template< + typename T, + bool = is_class_or_enum>::value, + typename = void + > + struct has_adl : std::false_type { + using category = return_category<0>; + }; + template + struct has_adl()))>> : std::true_type { + using category = return_category<1>; + }; -template< - typename T, - bool = is_class_or_enum>::value, - typename = void -> -struct iter_move_check_adaptors : std::false_type { - using category = return_category<0>; -}; -template -struct iter_move_check_adaptors()))>> : std::true_type { - using category = return_category<1, decltype(iter_move(std::declval()))>; -}; + template class Test, bool = dereferenceable::value /* false */> + struct deref_is : std::false_type {}; -template, dereferenceable>::value, typename = void> -struct iter_move_lvalue_deref_check : std::false_type { - using category = return_category<0>; -}; -template -struct iter_move_lvalue_deref_check()))>> : std::true_type { - using category = return_category<2, decltype(std::move(*std::declval()))>; -}; + template class Test> + struct deref_is : Test())> {}; -template, dereferenceable>::value> -struct iter_move_rvalue_deref_check : std::false_type { - using category = return_category<0>; -}; -template -struct iter_move_rvalue_deref_check : std::true_type { - using category = return_category<3, decltype(std::move(*std::declval()))>; -}; + template + struct category + : std::conditional_t< + has_adl::value, return_category<1>, + std::conditional_t< + deref_is::value, return_category<2>, + std::conditional_t< + dereferenceable::value, return_category<3>, + return_category<0> + >>> {}; -template -struct iter_move_category - : std::conditional_t< - iter_move_check_adaptors::value, typename iter_move_check_adaptors::category, - std::conditional_t< - iter_move_lvalue_deref_check::value, typename iter_move_lvalue_deref_check::category, - std::conditional_t< - iter_move_rvalue_deref_check::value, typename iter_move_rvalue_deref_check::category, - return_category<0> - >>> {}; - -template -constexpr R iter_move_impl(T&& t, return_category<1, R>) { - return iter_move(std::forward(t)); -} - -template -constexpr R iter_move_impl(T&& t, return_category<2, R>) { - return std::move(*t); -} - -template -constexpr R iter_move_impl(T&& t, return_category<3, R>) { - return std::move(*t); -} + template + constexpr decltype(auto) call(T&& t, return_category<1>) const { + return iter_move(std::forward(t)); + } + + template + constexpr decltype(auto) call(T&& t, return_category<2>) const { + return std::move(*std::forward(t)); + } -struct iter_move_niebloid { template - constexpr typename iter_move_category::return_type - operator()(T&& t) const { - return iter_move_impl(std::forward(t), detail::iter_move_category{}); + constexpr decltype(auto) call(T&& t, return_category<3>) const { + return *std::forward(t); + } + + public: + template::value > 0), int> = 0> + constexpr decltype(auto) operator()(T &&t) const { + return this->call(std::forward(t), category{}); } }; -} // namespace detail +} // namespace detail_iter_move -inline namespace niebloid { +namespace niebloid { /// @addtogroup iterator /// @{ @@ -99,12 +89,13 @@ inline namespace niebloid { /** `vccc::ranges::iter_move` is a \ref niebloid */ -VCCC_INLINE_OR_STATIC constexpr detail::iter_move_niebloid iter_move{}; +VCCC_INLINE_OR_STATIC constexpr detail_iter_move::iter_move_niebloid iter_move{}; /// @} /// @} } // inline namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__iterator/iter_swap.hpp b/include/vccc/__iterator/iter_swap.hpp index 44816c4c..90632c90 100644 --- a/include/vccc/__iterator/iter_swap.hpp +++ b/include/vccc/__iterator/iter_swap.hpp @@ -10,6 +10,7 @@ #include "vccc/__core/inline_or_static.hpp" #include "vccc/__concepts/swappable_with.hpp" +#include "vccc/__iterator/detail/iter_exchange_move.hpp" #include "vccc/__iterator/indirectly_movable_storable.hpp" #include "vccc/__iterator/indirectly_readable.hpp" #include "vccc/__iterator/iter_move.hpp" @@ -43,13 +44,10 @@ struct unqual_iter_swap : decltype(test_iter_swap(0)) {}; template struct unqual_iter_swap : decltype(test_iter_swap(0)) {}; +template, indirectly_readable>::value /* false */> +struct read_iter_swap : std::false_type{}; template -struct read_iter_swap_2 : swappable_with, iter_reference_t> {}; - -template, indirectly_readable>::value /* true */> -struct read_iter_swap : read_iter_swap_2 {}; -template -struct read_iter_swap : std::false_type {}; +struct read_iter_swap : swappable_with, iter_reference_t> {}; struct iter_swap_niebloid { template::value, int> = 0> @@ -75,20 +73,16 @@ struct iter_swap_niebloid { indirectly_movable_storable, indirectly_movable_storable >::value, int> = 0> - constexpr void operator()(I1&& x, I2&& y) const - noexcept(noexcept( iter_value_t(ranges::iter_move(x)) ) && - noexcept( *x = ranges::iter_move(y) ) && - noexcept( *std::forward(y) = std::declval>() )) + constexpr void operator()(I1&& i1, I2&& i2) const + noexcept(noexcept( *i1 = vccc::detail::iter_exchange_move(std::forward(i2), std::forward(i1)) )) { - iter_value_t old(ranges::iter_move(x)); - *x = ranges::iter_move(y); - *std::forward(y) = std::move(old); + (void)(*i1 = vccc::detail::iter_exchange_move(std::forward(i2), std::forward(i1))); } }; } // namespace detail_iter_swap -inline namespace niebloid { +namespace niebloid { /// @addtogroup iterator /// @{ @@ -97,7 +91,8 @@ VCCC_INLINE_OR_STATIC constexpr detail_iter_swap::iter_swap_niebloid iter_swap{} /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__iterator/move_iterator.hpp b/include/vccc/__iterator/move_iterator.hpp new file mode 100644 index 00000000..cd8acaa1 --- /dev/null +++ b/include/vccc/__iterator/move_iterator.hpp @@ -0,0 +1,109 @@ +// +// Created by YongGyu Lee on 4/15/24. +// + +#ifndef VCCC_ITERATOR_MOVE_ITERATOR_HPP_ +#define VCCC_ITERATOR_MOVE_ITERATOR_HPP_ + +#include +#include + +#include "vccc/__core/constexpr.hpp" +#include "vccc/__concepts/derived_from.hpp" +#include "vccc/__iterator/bidirectional_iterator.hpp" +#include "vccc/__iterator/forward_iterator.hpp" +#include "vccc/__iterator/indirectly_swappable.hpp" +#include "vccc/__iterator/iter_difference_t.hpp" +#include "vccc/__iterator/iter_move.hpp" +#include "vccc/__iterator/iter_rvalue_reference_t.hpp" +#include "vccc/__iterator/iter_value_t.hpp" +#include "vccc/__iterator/iterator_tag.hpp" +#include "vccc/__iterator/iterator_traits/cxx20_iterator_traits.hpp" +#include "vccc/__iterator/sized_sentinel_for.hpp" +#include "vccc/__iterator/move_sentinel.hpp" +#include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__iterator/random_access_iterator.hpp" +#include "vccc/__type_traits/negation.hpp" + +namespace vccc { + +/// @addtogroup iterator +/// @{ + +template +struct disable_sized_sentinel_for, std::move_iterator> + : negation> {}; + +#if __cplusplus < 202302L + +namespace detail { + +template::value /* false */> +struct move_iterator_category {}; + +template +struct move_iterator_category { + using iterator_category = std::conditional_t< + derived_from::iterator_category, random_access_iterator_tag>::value, random_access_iterator_tag, + typename cxx20_iterator_traits::iterator_category + >; +}; + +} // namespace detail + +template +struct cxx20_iterator_traits> + : detail::move_iterator_category +{ + using iterator_concept = + std::conditional_t< + random_access_iterator::value, random_access_iterator_tag, + std::conditional_t< + bidirectional_iterator::value, bidirectional_iterator_tag, + std::conditional_t< + forward_iterator::value, forward_iterator_tag, + input_iterator_tag + >>>; + using value_type = iter_value_t; + using difference_type = iter_difference_t; + using pointer = Iter; + using reference = iter_rvalue_reference_t; +}; + +namespace detail { + +template +struct is_primary_iterator_traits> : std::true_type {}; + +} // namespace detail + +#endif // __cplusplus < 202302L + +/// @} + +} // namespace vccc + + +#if __cplusplus < 202002L + +namespace std { + +template +constexpr vccc::iter_rvalue_reference_t iter_move(const move_iterator& i) + noexcept(noexcept(vccc::ranges::iter_move(i.base()))) +{ + return vccc::ranges::iter_move(i.base()); +} + +template::value, int> = 0> +constexpr void iter_swap(const move_iterator& x, const move_iterator& y) + noexcept(noexcept(vccc::ranges::iter_swap(x.base(), y.base()))) +{ + vccc::ranges::iter_swap(x.base(), y.base()); +} + +} // namespace std + +#endif + +#endif // VCCC_ITERATOR_MOVE_ITERATOR_HPP_ diff --git a/include/vccc/__iterator/next.hpp b/include/vccc/__iterator/next.hpp index 8bd37a81..c6fe8386 100644 --- a/include/vccc/__iterator/next.hpp +++ b/include/vccc/__iterator/next.hpp @@ -52,7 +52,7 @@ struct next_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup iterator /// @{ @@ -67,7 +67,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::next_niebloid next{}; /// @} /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__iterator/prev.hpp b/include/vccc/__iterator/prev.hpp index 21c05d4b..7e2b87a5 100644 --- a/include/vccc/__iterator/prev.hpp +++ b/include/vccc/__iterator/prev.hpp @@ -42,7 +42,7 @@ struct prev_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup iterator /// @{ @@ -55,7 +55,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::prev_niebloid prev{}; /// @} /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__iterator/projected.hpp b/include/vccc/__iterator/projected.hpp index 24e8e5d9..91b2b63f 100644 --- a/include/vccc/__iterator/projected.hpp +++ b/include/vccc/__iterator/projected.hpp @@ -5,6 +5,8 @@ #ifndef VCCC_ITERATOR_PROJECTED_HPP #define VCCC_ITERATOR_PROJECTED_HPP +#include "vccc/__core/ignore_dumb_diagnostics_push.hpp" + #include "vccc/__iterator/indirect_result_t.hpp" #include "vccc/__iterator/indirectly_readable.hpp" #include "vccc/__iterator/indirectly_regular_unary_invocable.hpp" @@ -75,4 +77,5 @@ using projectable = has_typename_type>; } // namespace vccc +#include "vccc/__core/ignore_dumb_diagnostics_pop.hpp" #endif // VCCC_ITERATOR_PROJECTED_HPP diff --git a/include/vccc/__iterator/reverse_iterator.hpp b/include/vccc/__iterator/reverse_iterator.hpp new file mode 100644 index 00000000..3ea035af --- /dev/null +++ b/include/vccc/__iterator/reverse_iterator.hpp @@ -0,0 +1,102 @@ +// +// Created by YongGyu Lee on 4/15/24. +// + +#ifndef VCCC_ITERATOR_REVERSE_ITERATOR_HPP_ +#define VCCC_ITERATOR_REVERSE_ITERATOR_HPP_ + + +#include +#include + +#include "vccc/__concepts/derived_from.hpp" +#include "vccc/__iterator/indirectly_swappable.hpp" +#include "vccc/__iterator/iter_difference_t.hpp" +#include "vccc/__iterator/iter_move.hpp" +#include "vccc/__iterator/iter_reference_t.hpp" +#include "vccc/__iterator/iter_rvalue_reference_t.hpp" +#include "vccc/__iterator/iter_swap.hpp" +#include "vccc/__iterator/iter_value_t.hpp" +#include "vccc/__iterator/iterator_tag.hpp" +#include "vccc/__iterator/iterator_traits/cxx20_iterator_traits.hpp" +#include "vccc/__iterator/random_access_iterator.hpp" +#include "vccc/__iterator/sized_sentinel_for.hpp" +#include "vccc/__type_traits/negation.hpp" + +namespace vccc { + +/// @addtogroup iterator +/// @{ + +template +struct disable_sized_sentinel_for, std::reverse_iterator> + : negation> {}; + +// iterator_traits +#if __cplusplus < 202002L + +template +struct cxx20_iterator_traits> { + using iterator_concept = std::conditional_t< + random_access_iterator::value, + random_access_iterator_tag, + bidirectional_iterator_tag + >; + using iterator_category = std::conditional_t< + derived_from::iterator_category, random_access_iterator_tag>::value, + random_access_iterator_tag, + typename cxx20_iterator_traits::iterator_category + >; + using value_type = iter_value_t; + using difference_type = iter_difference_t; + using pointer = typename cxx20_iterator_traits::pointer; + using reference = iter_reference_t; +}; + +namespace detail { + +template +struct is_primary_iterator_traits>> : std::true_type {}; + +} // namespace detail + +#endif // __cplusplus < 202002L + +/// @} + +} // namespace vccc + +// iter_move, iter_swap +#if __cplusplus < 202002L + +namespace std { + +template +constexpr vccc::iter_rvalue_reference_t iter_move(const std::reverse_iterator& i) + noexcept( + std::is_nothrow_copy_constructible::value && + noexcept(vccc::ranges::iter_move(--std::declval())) + ) +{ + auto tmp = i.base(); + return vccc::ranges::iter_move(--tmp); +} + +template::value, int> = 0> +constexpr void iter_swap(const reverse_iterator& x, const reverse_iterator& y) + noexcept( + std::is_nothrow_copy_constructible::value && + std::is_nothrow_copy_constructible::value && + noexcept(vccc::ranges::iter_swap(--std::declval(), --std::declval())) + ) +{ + auto tmp_x = x.base(); + auto tmp_y = y.base(); + vccc::ranges::iter_swap(--tmp_x, --tmp_y); +} + +} // namespace std + +#endif // __cplusplus < 202002L + +#endif // VCCC_ITERATOR_REVERSE_ITERATOR_HPP_ diff --git a/include/vccc/__memory/destroy.hpp b/include/vccc/__memory/destroy.hpp index ae00eb69..49ffbebe 100644 --- a/include/vccc/__memory/destroy.hpp +++ b/include/vccc/__memory/destroy.hpp @@ -11,6 +11,9 @@ namespace vccc { +/// @addtogroup iterator +/// @{ + template VCCC_CONSTEXPR_AFTER_CXX20 void destroy(ForwardIt first, ForwardIt last) { for (; first != last; ++first) { @@ -18,6 +21,7 @@ VCCC_CONSTEXPR_AFTER_CXX20 void destroy(ForwardIt first, ForwardIt last) { } } +/// @} } // namespace vccc diff --git a/include/vccc/__memory/to_address.hpp b/include/vccc/__memory/to_address.hpp index 34b6b1d8..8e14ad26 100644 --- a/include/vccc/__memory/to_address.hpp +++ b/include/vccc/__memory/to_address.hpp @@ -30,6 +30,9 @@ constexpr auto to_address_fancy(const T& p, std::false_type /* has_to_address */ } // namespace detail +/// @addtogroup iterator +/// @{ + template constexpr T* to_address(T* p) noexcept { static_assert(!std::is_function::value, "T must not be a pointer to function"); @@ -41,6 +44,8 @@ constexpr auto to_address(const T& p) noexcept { return detail::to_address_fancy(p, detail::has_to_address{}); } +/// @} + namespace detail { template diff --git a/include/vccc/__numeric/saturate_cast.hpp b/include/vccc/__numeric/saturate_cast.hpp new file mode 100644 index 00000000..4896f501 --- /dev/null +++ b/include/vccc/__numeric/saturate_cast.hpp @@ -0,0 +1,73 @@ +// +// Created by YongGyu Lee on 4/15/24. +// + +#ifndef VCCC_NUMERIC_SATURATE_CAST_HPP_ +#define VCCC_NUMERIC_SATURATE_CAST_HPP_ + +#include +#include + +#include "vccc/__type_traits/bool_constant.hpp" +#include "vccc/__type_traits/conjunction.hpp" + +namespace vccc { +namespace detail { + +// high bit -> low bit +template +inline constexpr To saturate_cast_impl(From x, Any, Any, std::true_type /* digit < digit */) noexcept { + if (x < static_cast((std::numeric_limits::min)())) + return (std::numeric_limits::min)(); + if (x > static_cast((std::numeric_limits::max)())) + return (std::numeric_limits::max)(); + return static_cast(x); +} + +// low bit -> high bit +template +inline constexpr To saturate_cast_impl(From x, Any, Any, std::false_type /* digit < digit */) noexcept { + return static_cast(x); +} + +// unsigned -> signed +template +inline constexpr To saturate_cast_impl(From x, std::false_type /* signed */, std::true_type /* signed */, Any) noexcept { + if (x > std::make_unsigned_t((std::numeric_limits::max)())) + return (std::numeric_limits::max)(); + return static_cast(x); +} + +// signed -> unsigned +template +inline constexpr To saturate_cast_impl(From x, std::true_type /* signed */, std::false_type /* signed */, Any) noexcept { + if (x < 0) + return 0; + if (std::make_unsigned_t(x) > (std::numeric_limits::max)()) + return (std::numeric_limits::max)(); + return static_cast(x); +} + +} // namespace detail + +/// @addtogroup iterator +/// @{ + +template, + std::is_integral +>::value, int> = 0> +inline constexpr To saturate_cast(From x) noexcept { + return vccc::detail::saturate_cast_impl( + x, + std::is_signed{}, + std::is_signed{}, + vccc::bool_constant<((std::numeric_limits::digits) < (std::numeric_limits::digits))>{} + ); +} + +/// @} + +} // namespace vccc + +#endif // VCCC_NUMERIC_SATURATE_CAST_HPP_ diff --git a/include/vccc/__ranges/as_const_pointer.hpp b/include/vccc/__ranges/as_const_pointer.hpp index a2127e2f..b1ec3cce 100644 --- a/include/vccc/__ranges/as_const_pointer.hpp +++ b/include/vccc/__ranges/as_const_pointer.hpp @@ -8,11 +8,16 @@ namespace vccc { namespace ranges { +/// @addtogroup ranges +/// @{ + template constexpr auto as_const_pointer(const T* p) noexcept { return p; } +/// @} + } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/begin.hpp b/include/vccc/__ranges/begin.hpp index be753313..57717eda 100644 --- a/include/vccc/__ranges/begin.hpp +++ b/include/vccc/__ranges/begin.hpp @@ -100,7 +100,7 @@ struct begin_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -116,7 +116,8 @@ Returns an iterator to the first element of the argument. VCCC_INLINE_OR_STATIC constexpr detail::begin_niebloid begin{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/cbegin.hpp b/include/vccc/__ranges/cbegin.hpp index b27366fe..5d313f01 100644 --- a/include/vccc/__ranges/cbegin.hpp +++ b/include/vccc/__ranges/cbegin.hpp @@ -30,7 +30,7 @@ struct cbegin_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -47,7 +47,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::cbegin_niebloid cbegin{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/cdata.hpp b/include/vccc/__ranges/cdata.hpp index 68665996..0bca83f2 100644 --- a/include/vccc/__ranges/cdata.hpp +++ b/include/vccc/__ranges/cdata.hpp @@ -32,7 +32,7 @@ struct cdata_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -41,7 +41,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::cdata_niebloid cdata{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/cend.hpp b/include/vccc/__ranges/cend.hpp index bcdd7570..c35bd877 100644 --- a/include/vccc/__ranges/cend.hpp +++ b/include/vccc/__ranges/cend.hpp @@ -30,7 +30,7 @@ struct cend_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -47,7 +47,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::cend_niebloid cend{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/crbegin.hpp b/include/vccc/__ranges/crbegin.hpp index 939d3e21..83c5255d 100644 --- a/include/vccc/__ranges/crbegin.hpp +++ b/include/vccc/__ranges/crbegin.hpp @@ -30,7 +30,7 @@ struct crbegin_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -39,7 +39,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::crbegin_niebloid crbegin{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/crend.hpp b/include/vccc/__ranges/crend.hpp index 8e0c7997..d13c08ff 100644 --- a/include/vccc/__ranges/crend.hpp +++ b/include/vccc/__ranges/crend.hpp @@ -30,7 +30,7 @@ struct crend_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -39,7 +39,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::crend_niebloid crend{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/data.hpp b/include/vccc/__ranges/data.hpp index 346ef0be..4c17906b 100644 --- a/include/vccc/__ranges/data.hpp +++ b/include/vccc/__ranges/data.hpp @@ -84,7 +84,7 @@ struct data_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -104,7 +104,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::data_niebloid data{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/distance.hpp b/include/vccc/__ranges/distance.hpp index b2d9e226..0e7361f3 100644 --- a/include/vccc/__ranges/distance.hpp +++ b/include/vccc/__ranges/distance.hpp @@ -64,7 +64,7 @@ struct distance_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -73,7 +73,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::distance_niebloid distance{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/empty.hpp b/include/vccc/__ranges/empty.hpp index 3862b630..e3280ffb 100644 --- a/include/vccc/__ranges/empty.hpp +++ b/include/vccc/__ranges/empty.hpp @@ -102,7 +102,7 @@ struct empty_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -117,7 +117,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::empty_niebloid empty{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/end.hpp b/include/vccc/__ranges/end.hpp index f2ed991c..89655a65 100644 --- a/include/vccc/__ranges/end.hpp +++ b/include/vccc/__ranges/end.hpp @@ -104,7 +104,7 @@ struct end_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -121,7 +121,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::end_niebloid end{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/from_range.hpp b/include/vccc/__ranges/from_range.hpp index 6f520e34..f6ac11c6 100644 --- a/include/vccc/__ranges/from_range.hpp +++ b/include/vccc/__ranges/from_range.hpp @@ -13,13 +13,12 @@ namespace vccc { -namespace ranges { /// @addtogroup ranges /// @{ -#if __cplusplus >= 202302L -using from_range_t = std::ranges::from_range_t; +#if __cplusplus >= 202302L && defined(__cpp_lib_containers_ranges) +using from_range_t = std::from_range_t; #else struct from_range_t { explicit from_range_t() = default; @@ -30,7 +29,6 @@ VCCC_INLINE_OR_STATIC constexpr from_range_t from_range{}; /// @} -} // namespace ranges } // namespace vccc #endif // VCCC_RANGES_FROM_RANGE_HPP_ diff --git a/include/vccc/__ranges/non_propagating_cache.hpp b/include/vccc/__ranges/non_propagating_cache.hpp index d0e113a5..676dd5d3 100644 --- a/include/vccc/__ranges/non_propagating_cache.hpp +++ b/include/vccc/__ranges/non_propagating_cache.hpp @@ -24,6 +24,9 @@ struct constructible_from_deref : constructible_from class non_propagating_cache : private optional { @@ -46,7 +49,8 @@ class non_propagating_cache : private optional { non_propagating_cache() = default; - constexpr non_propagating_cache(const non_propagating_cache&) noexcept {} + constexpr non_propagating_cache(const non_propagating_cache&) noexcept + : base() {} constexpr non_propagating_cache(non_propagating_cache&& other) noexcept { other.reset(); } @@ -70,6 +74,8 @@ class non_propagating_cache : private optional { } }; +/// @} + } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/output_range.hpp b/include/vccc/__ranges/output_range.hpp index 427ef7cd..30ee69ca 100644 --- a/include/vccc/__ranges/output_range.hpp +++ b/include/vccc/__ranges/output_range.hpp @@ -22,9 +22,14 @@ struct output_range_impl : output_iterator, T> {}; } // namespace detail +/// @addtogroup ranges +/// @{ + template struct output_range : detail::output_range_impl {}; +/// @} + } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/possibly_const_range.hpp b/include/vccc/__ranges/possibly_const_range.hpp index aedacefb..73d6fd17 100644 --- a/include/vccc/__ranges/possibly_const_range.hpp +++ b/include/vccc/__ranges/possibly_const_range.hpp @@ -28,11 +28,16 @@ constexpr auto& possibly_const_range_impl(R& r, std::false_type) noexcept { } // namespace detail +/// @addtogroup ranges +/// @{ + template::value, int> = 0> constexpr auto& possibly_const_range(R& r) noexcept { return detail::possibly_const_range_impl(r, conjunction, negation>>{}); } +/// @} + } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/range_adaptor.hpp b/include/vccc/__ranges/range_adaptor.hpp index db4724f2..34bc6801 100644 --- a/include/vccc/__ranges/range_adaptor.hpp +++ b/include/vccc/__ranges/range_adaptor.hpp @@ -18,6 +18,9 @@ namespace vccc { namespace ranges { +/// @addtogroup ranges +/// @{ + template class range_adaptor : public range_adaptor_closure> { public: @@ -61,6 +64,8 @@ class range_adaptor : public range_adaptor_closure args_; }; +/// @} + } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/rbegin.hpp b/include/vccc/__ranges/rbegin.hpp index 6dc7859a..4d2aef3d 100644 --- a/include/vccc/__ranges/rbegin.hpp +++ b/include/vccc/__ranges/rbegin.hpp @@ -85,7 +85,7 @@ struct rbegin_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -94,7 +94,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::rbegin_niebloid rbegin{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/rend.hpp b/include/vccc/__ranges/rend.hpp index 21301bcf..c3a10826 100644 --- a/include/vccc/__ranges/rend.hpp +++ b/include/vccc/__ranges/rend.hpp @@ -90,7 +90,7 @@ struct rend_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -99,7 +99,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::rend_niebloid rend{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/simple_view.hpp b/include/vccc/__ranges/simple_view.hpp index 64f7952e..985293c2 100644 --- a/include/vccc/__ranges/simple_view.hpp +++ b/include/vccc/__ranges/simple_view.hpp @@ -17,6 +17,9 @@ namespace vccc { namespace ranges { +/// @addtogroup ranges +/// @{ + template, range>::value /* true */> struct simple_view : conjunction< @@ -27,6 +30,8 @@ struct simple_view template struct simple_view : std::false_type {}; +/// @} + } // namespace vccc } // namespace ranges diff --git a/include/vccc/__ranges/size.hpp b/include/vccc/__ranges/size.hpp index a369b3d8..0fc9f8a6 100644 --- a/include/vccc/__ranges/size.hpp +++ b/include/vccc/__ranges/size.hpp @@ -131,7 +131,7 @@ struct size_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -146,7 +146,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::size_niebloid size{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/ssize.hpp b/include/vccc/__ranges/ssize.hpp index 73150317..ed9fd536 100644 --- a/include/vccc/__ranges/ssize.hpp +++ b/include/vccc/__ranges/ssize.hpp @@ -42,7 +42,7 @@ struct ssize_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -57,7 +57,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::ssize_niebloid ssize{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/subrange.hpp b/include/vccc/__ranges/subrange.hpp index b4c0e26e..dce8a77c 100644 --- a/include/vccc/__ranges/subrange.hpp +++ b/include/vccc/__ranges/subrange.hpp @@ -137,6 +137,9 @@ struct subrange_ctor_range : std::false_type {}; } +/// @addtogroup ranges +/// @{ + template< typename I, typename S = I, @@ -167,7 +170,7 @@ class subrange bool_constant< K == subrange_kind::sized > >::value, int> = 0> constexpr subrange(I2 i, S s, detail::make_unsigned_like_t> n) - : iterator_(std::move(i)), sentinel_(std::move(s)), size_base(in_place, n) {} + : size_base(in_place, n), iterator_(std::move(i)), sentinel_(std::move(s)) {} template, @@ -378,6 +381,8 @@ constexpr auto get(subrange&& r) { template struct enable_borrowed_range> : std::true_type {}; +/// @} + } // namespace ranges namespace internal { diff --git a/include/vccc/__ranges/views/all.hpp b/include/vccc/__ranges/views/all.hpp index 02c5a018..77881455 100644 --- a/include/vccc/__ranges/views/all.hpp +++ b/include/vccc/__ranges/views/all.hpp @@ -67,7 +67,7 @@ class all_adaptor_closure : public range_adaptor_closure { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges /// @{ @@ -83,7 +83,8 @@ VCCC_INLINE_OR_STATIC constexpr detail::all_adaptor_closure all{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; namespace detail { diff --git a/include/vccc/__ranges/views/cartesian_product_view.hpp b/include/vccc/__ranges/views/cartesian_product_view.hpp index de20b02a..946dabab 100644 --- a/include/vccc/__ranges/views/cartesian_product_view.hpp +++ b/include/vccc/__ranges/views/cartesian_product_view.hpp @@ -32,6 +32,7 @@ #include "vccc/__ranges/sized_range.hpp" #include "vccc/__ranges/view.hpp" #include "vccc/__ranges/view_interface.hpp" +#include "vccc/__tuple/tuple_transform.hpp" #include "vccc/__type_traits/bool_constant.hpp" #include "vccc/__type_traits/conjunction.hpp" #include "vccc/__type_traits/disjunction.hpp" @@ -379,33 +380,27 @@ class cartesian_product_view : public view_interface >>, - // std::is_nothrow_move_constructible >>... - // >::value - // ) - // { - // return detail::cartesian_tuple_transform(ranges::iter_move, i.current_); - // } - - // TODO: Solve "redefinition of 'iter_swap' as different kind of symbol" -#if __cplusplus >= 202002L + friend constexpr auto iter_move(const iterator& i) + noexcept( + noexcept(vccc::tuple_transform(i.current_, ranges::iter_move)) && + conjunction< + std::is_nothrow_move_constructible >>, + std::is_nothrow_move_constructible >>... + >::value + ) + { + return vccc::tuple_transform(i.current_, ranges::iter_move); + } + + template, + indirectly_swappable< iterator_t> >, + indirectly_swappable< iterator_t> >... + >::value, int> = 0> friend constexpr void iter_swap(const iterator& x, const iterator& y) - noexcept(noexcept(x.iter_swap_impl(y))) - requires( - conjunction< - indirectly_swappable< iterator_t> >, - indirectly_swappable< iterator_t> >... - >::value - ) + noexcept(noexcept(x.iter_swap_impl(y))) { x.iter_swap_impl(y); } -#endif private: template diff --git a/include/vccc/__ranges/views/drop_view.hpp b/include/vccc/__ranges/views/drop_view.hpp index 149eb770..e100f50c 100644 --- a/include/vccc/__ranges/views/drop_view.hpp +++ b/include/vccc/__ranges/views/drop_view.hpp @@ -56,6 +56,9 @@ class drop_view_cached_begin { } // namespace detail +/// @addtogroup ranges +/// @{ + template class drop_view : public ranges::view_interface> @@ -143,6 +146,8 @@ drop_view(R&&, range_difference_t) -> drop_view>; template struct enable_borrowed_range> : enable_borrowed_range {}; +/// @} + } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/views/elements_view.hpp b/include/vccc/__ranges/views/elements_view.hpp index a7c5ed01..4a2f8c9c 100644 --- a/include/vccc/__ranges/views/elements_view.hpp +++ b/include/vccc/__ranges/views/elements_view.hpp @@ -61,20 +61,20 @@ template struct returnable_element : move_constructible> {}; -template< - typename Base, - std::size_t N, - typename C = typename cxx20_iterator_traits>::iterator_category, - bool = forward_range::value /* false */ -> +// Not defined, if Base does not model forward_range +template::value /* false */> struct elements_view_iterator_category { #if __cplusplus < 202002L using iterator_category = iterator_ignore; #endif }; -template -struct elements_view_iterator_category { +template +struct elements_view_iterator_category { + private: + using C = typename cxx20_iterator_traits>::iterator_category; + + public: using iterator_category = std::conditional_t< std::is_rvalue_reference(*std::declval&>()))>::value, input_iterator_tag, @@ -86,6 +86,9 @@ struct elements_view_iterator_category { } // namespace detail +/// @addtogroup ranges +/// @{ + template class elements_view : public view_interface> { public: @@ -100,7 +103,7 @@ class elements_view : public view_interface> { template class iterator : public detail::elements_view_iterator_category, N> { - using Base = std::conditional_t; + using Base = maybe_const; template friend class sentinel; template::value /* true */> @@ -267,7 +270,7 @@ class elements_view : public view_interface> { template class sentinel { - using Base = std::conditional_t; + using Base = maybe_const; public: sentinel() = default; @@ -420,6 +423,8 @@ class elements_view : public view_interface> { template struct enable_borrowed_range> : enable_borrowed_range {}; +/// @} + } // namespace ranges } // namespace vccc diff --git a/include/vccc/__ranges/views/enumerate_view.hpp b/include/vccc/__ranges/views/enumerate_view.hpp index ebd49a55..f293b8f0 100644 --- a/include/vccc/__ranges/views/enumerate_view.hpp +++ b/include/vccc/__ranges/views/enumerate_view.hpp @@ -12,6 +12,7 @@ #include "vccc/__concepts/convertible_to.hpp" #include "vccc/__concepts/move_constructible.hpp" #include "vccc/__iterator/iterator_tag.hpp" +#include "vccc/__iterator/iter_move.hpp" #include "vccc/__iterator/sized_sentinel_for.hpp" #include "vccc/__ranges/begin.hpp" #include "vccc/__ranges/bidirectional_range.hpp" @@ -219,16 +220,15 @@ class enumerate_view : public view_interface> { return i.pos_ - j.pos_; } - // TODO: Solve "redefinition of 'iter_move' as different kind of symbol" in Android NDK 21.1.6352462 - // friend constexpr auto iter_move(const iterator& i) - // noexcept( - // noexcept(ranges::iter_move(i.current_)) && - // std::is_nothrow_move_constructible< - // range_rvalue_reference_t>::value - // ) - // { - // return std::tuple>(i.pos_, ranges::iter_move(i.current_)); - // } + friend constexpr auto iter_move(const iterator& i) + noexcept( + noexcept(ranges::iter_move(i.current_)) && + std::is_nothrow_move_constructible< + range_rvalue_reference_t>::value + ) + { + return std::tuple>(i.pos_, ranges::iter_move(i.current_)); + } private: iterator_t current_; @@ -237,7 +237,7 @@ class enumerate_view : public view_interface> { template class sentinel { - using Base = std::conditional_t;\ + using Base = maybe_const; friend class enumerate_view; public: diff --git a/include/vccc/__ranges/views/filter_view.hpp b/include/vccc/__ranges/views/filter_view.hpp index 98c3c2a4..46727560 100644 --- a/include/vccc/__ranges/views/filter_view.hpp +++ b/include/vccc/__ranges/views/filter_view.hpp @@ -73,19 +73,19 @@ class filter_view_cache { } }; -template< - typename V, - typename C = typename cxx20_iterator_traits>::iterator_category, - bool = forward_range::value /* false */ -> +template::value /* false */> struct filter_view_iterator_category { #if __cplusplus < 202002L using iterator_category = iterator_ignore; #endif }; -template -struct filter_view_iterator_category { +template +struct filter_view_iterator_category { + private: + using C = typename cxx20_iterator_traits>::iterator_category; + + public: using iterator_category = std::conditional_t< derived_from::value, bidirectional_iterator_tag, @@ -205,22 +205,18 @@ class filter_view : public view_interface>, detail::filter_ return !(x == y); } - // TODO: Solve "redefinition of 'iter_move' as different kind of symbol" in Android NDK 21.1.6352462 - // friend constexpr range_rvalue_reference_t - // iter_move(const iterator& i) noexcept(noexcept( ranges::iter_move(i.current_) )) { - // return ranges::iter_move(i.current_); - // } + friend constexpr range_rvalue_reference_t + iter_move(const iterator& i) noexcept(noexcept( ranges::iter_move(i.current_) )) { + return ranges::iter_move(i.current_); + } - // TODO: Solve "redefinition of 'iter_swap' as different kind of symbol" // TODO: Solve "const_cast from rvalue to reference type" in AppleClang 14.0.3.14030022 -#if __cplusplus >= 202002L - // friend constexpr void iter_swap(const iterator& x, const iterator& y) - // noexcept(noexcept(ranges::iter_swap(x.current_, y.current_))) - // requires(indirectly_swappable>::value) - // { - // ranges::iter_swap(x.current_, y.current_); - // } -#endif + template>::value, int> = 0> + friend constexpr void iter_swap(const iterator& x, const iterator& y) + noexcept(noexcept(ranges::iter_swap(x.current_, y.current_))) + { + ranges::iter_swap(x.current_, y.current_); + } private: iterator_t current_; @@ -264,7 +260,7 @@ class filter_view : public view_interface>, detail::filter_ constexpr explicit filter_view(V base, Pred pred) : base_(std::move(base)), pred_(std::move(pred)) {} - template::value, int> = 0> + template::value, int> = 0> constexpr V base() const & { return base_; } diff --git a/include/vccc/__ranges/views/join_view.hpp b/include/vccc/__ranges/views/join_view.hpp index 6373155c..bfcf33da 100644 --- a/include/vccc/__ranges/views/join_view.hpp +++ b/include/vccc/__ranges/views/join_view.hpp @@ -12,8 +12,11 @@ #include "vccc/__concepts/default_initializable.hpp" #include "vccc/__concepts/derived_from.hpp" #include "vccc/__concepts/equality_comparable.hpp" +#include "vccc/__iterator/indirectly_swappable.hpp" #include "vccc/__iterator/iterator_tag.hpp" #include "vccc/__iterator/iterator_traits/cxx20_iterator_traits.hpp" +#include "vccc/__iterator/iter_move.hpp" +#include "vccc/__iterator/iter_swap.hpp" #include "vccc/__memory/addressof.hpp" #include "vccc/__ranges/bidirectional_range.hpp" #include "vccc/__ranges/common_range.hpp" @@ -57,15 +60,21 @@ using join_view_iterator_concept = input_iterator_tag >>; -template -struct join_view_iterator_category_impl { +// Defined only if IteratorConcept models forward_iterator_tag +template> +struct join_view_iterator_category { #if __cplusplus < 202002L using iterator_category = iterator_ignore; #endif }; -template -struct join_view_iterator_category_impl { +template +struct join_view_iterator_category { + private: + using OuterC = typename cxx20_iterator_traits>::iterator_category; + using InnerC = typename cxx20_iterator_traits>>::iterator_category; + + public: using iterator_category = std::conditional_t< conjunction< @@ -73,24 +82,16 @@ struct join_view_iterator_category_impl { derived_from >::value, bidirectional_iterator_tag, - std::conditional_t< - conjunction< - derived_from, - derived_from - >::value, - forward_iterator_tag, - input_iterator_tag - >>; + std::conditional_t< + conjunction< + derived_from, + derived_from + >::value, + forward_iterator_tag, + input_iterator_tag + >>; }; -template -struct join_view_iterator_category - : join_view_iterator_category_impl< - join_view_iterator_concept, - typename cxx20_iterator_traits>::iterator_category, - typename cxx20_iterator_traits>>::iterator_category - > {}; - } // namespace detail /// @addtogroup ranges @@ -255,14 +256,18 @@ class join_view : public view_interface> { return !(x == y); } - // TODO: Solve "redefinition of 'iter_move' as different kind of symbol" in Android NDK 21.1.6352462 - // friend constexpr decltype(auto) iter_move(const iterator& i) - // noexcept(noexcept(ranges::iter_move(*i.inner_))) - // { - // return ranges::iter_move(*i.inner_); - // } + friend constexpr decltype(auto) iter_move(const iterator& i) + noexcept(noexcept(ranges::iter_move(*i.inner_))) + { + return ranges::iter_move(*i.inner_); + } - // TODO: Implement iter_swap + template::value, int> = 0> + friend constexpr void iter_swap(const iterator& x, const iterator& y) + noexcept(noexcept(ranges::iter_swap(*x.inner_, *y.inner_))) + { + ranges::iter_swap(x.inner_, y.inner_); + } private: constexpr OuterIter& get_outer() noexcept { @@ -346,6 +351,14 @@ class join_view : public view_interface> { return x == 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); + } + private: sentinel_t end_; }; diff --git a/include/vccc/__ranges/views/join_with_view.hpp b/include/vccc/__ranges/views/join_with_view.hpp index 83d7ce25..bb2bb1bd 100644 --- a/include/vccc/__ranges/views/join_with_view.hpp +++ b/include/vccc/__ranges/views/join_with_view.hpp @@ -15,6 +15,8 @@ #include "vccc/__concepts/equality_comparable.hpp" #include "vccc/__iterator/iterator_tag.hpp" #include "vccc/__iterator/iterator_traits/cxx20_iterator_traits.hpp" +#include "vccc/__iterator/iter_move.hpp" +#include "vccc/__iterator/iter_swap.hpp" #include "vccc/__memory/addressof.hpp" #include "vccc/__ranges/begin.hpp" #include "vccc/__ranges/bidirectional_range.hpp" @@ -27,6 +29,7 @@ #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_rvalue_reference_t.hpp" #include "vccc/__ranges/range_value_t.hpp" #include "vccc/__ranges/sentinel_t.hpp" #include "vccc/__ranges/view.hpp" @@ -350,6 +353,18 @@ class join_with_view : public detail::join_with_view_base, range_rvalue_reference_t>; + return i.inner_it_.visit([](auto&& i) -> R { + return ranges::iter_move(std::forward(i)); + }); + } + + template, iterator_t>, std::enable_if_t = 0> + friend constexpr void iter_swap(const iterator& x, const iterator& y) { + vccc::visit(ranges::iter_swap, x.inner_it_, y.inner_it_); + } + private: template::value, int> = 0> constexpr iterator(Parent& parent, iterator_t outer_it) @@ -394,22 +409,22 @@ class join_with_view : public detail::join_with_view_base::value, int> = 0> - constexpr auto& update_inner() { + constexpr decltype(auto) update_inner() { return *get_outer(); } template::value == false, int> = 0> - constexpr auto& update_inner() { + constexpr decltype(auto) update_inner() { return parent_->inner_base_.emplace_deref(get_outer()).val; } template::value, int> = 0> - constexpr auto& get_inner() noexcept { + constexpr decltype(auto) get_inner() noexcept { return *get_outer(); } template::value == false, int> = 0> - constexpr auto& get_inner() noexcept { + constexpr decltype(auto) get_inner() noexcept { return *parent_->inner_base_.val; } diff --git a/include/vccc/__ranges/views/single.hpp b/include/vccc/__ranges/views/single.hpp index d4975284..d311e087 100644 --- a/include/vccc/__ranges/views/single.hpp +++ b/include/vccc/__ranges/views/single.hpp @@ -96,7 +96,7 @@ struct single_niebloid { } // namespace detail -inline namespace niebloid { +namespace niebloid { /// @addtogroup ranges_single_view__class__Factories /// @{ @@ -105,7 +105,9 @@ VCCC_INLINE_OR_STATIC constexpr detail::single_niebloid single{}; /// @} -} // inline namespace niebloid +} // namespace niebloid +using namespace niebloid; + } // namespace vccc } // namespace ranges } // namespace views diff --git a/include/vccc/__ranges/views/take_view.hpp b/include/vccc/__ranges/views/take_view.hpp index a4f99d5f..30ffe296 100644 --- a/include/vccc/__ranges/views/take_view.hpp +++ b/include/vccc/__ranges/views/take_view.hpp @@ -28,6 +28,7 @@ #include "vccc/__ranges/views/all.hpp" #include "vccc/__type_traits/bool_constant.hpp" #include "vccc/__type_traits/conjunction.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" @@ -45,7 +46,7 @@ class take_view : public view_interface> { template class sentinel { - using Base = std::conditional_t; + using Base = maybe_const; public: sentinel() = default; @@ -70,11 +71,21 @@ class take_view : public view_interface> { return y.count() == 0 || y.base() == x.end_; } + friend constexpr bool + operator==(const sentinel& x, const counted_iterator>& y) { + return y == x; + } + friend constexpr bool operator!=(const counted_iterator>& y, const sentinel& x) { return !(y == x); } + friend constexpr bool + operator!=(const sentinel& x, const counted_iterator>& y) { + return !(y == x); + } + template, sentinel_for< sentinel_t, @@ -86,6 +97,16 @@ class take_view : public view_interface> { return y.count() == 0 || y.base() == x.end_; } + template, + sentinel_for< sentinel_t, + iterator_t> > + >::value, int> = 0> + friend constexpr bool + operator==(const sentinel& x, const counted_iterator>>& y) { + return y == x; + } + template, sentinel_for< sentinel_t, @@ -93,7 +114,16 @@ class take_view : public view_interface> { >::value, int> = 0> friend constexpr bool operator!=(const counted_iterator>>& y, const sentinel& x) { - using namespace vccc::rel_ops; + return !(y == x); + } + + template, + sentinel_for< sentinel_t, + iterator_t> > + >::value, int> = 0> + friend constexpr bool + operator!=(const sentinel& x, const counted_iterator>>& y) { return !(y == x); } diff --git a/include/vccc/__ranges/views/transform_view.hpp b/include/vccc/__ranges/views/transform_view.hpp index d632e188..8f29a314 100644 --- a/include/vccc/__ranges/views/transform_view.hpp +++ b/include/vccc/__ranges/views/transform_view.hpp @@ -34,6 +34,7 @@ #include "vccc/__type_traits/bool_constant.hpp" #include "vccc/__type_traits/conjunction.hpp" #include "vccc/__type_traits/is_invocable.hpp" +#include "vccc/__type_traits/maybe_const.hpp" #include "vccc/__type_traits/remove_cvref.hpp" #include "vccc/__utility/cxx20_rel_ops.hpp" @@ -84,12 +85,17 @@ class transform_view : public view_interface> { public: template class iterator; + template friend class iterator; + template class sentinel; template class iterator : public transform_view_iterator_category> { using Parent = std::conditional_t; - using Base = std::conditional_t; + using Base = maybe_const; + + template friend class sentinel; + friend class transform_view; public: using iterator_concept = std::conditional_t< @@ -223,16 +229,21 @@ class transform_view : public view_interface> { return x.current_ - y.current_; } - // TODO: Solve "redefinition of 'iter_move' as different kind of symbol" in Android NDK 21.1.6352462 - // friend constexpr decltype(auto) iter_move(const iterator& i) - // noexcept(noexcept(*i)) { - // return std::is_lvalue_reference::value ? std::move(*i) : *i; - // } + friend constexpr decltype(auto) iter_move(const iterator& i) + noexcept(noexcept(vccc::invoke(std::declval(), *i.current_))) + { + return iter_move_ref(*i); + } private: - template - friend class sentinel; - friend class transform_view; + template::value, int> = 0> + static constexpr decltype(auto) iter_move_ref(T&& ref) { + return std::forward(ref); + } + template + static constexpr decltype(auto) iter_move_ref(T& ref) { + return std::move(ref); + } iterator_t current_; Parent* parent_ = nullptr; @@ -241,7 +252,7 @@ class transform_view : public view_interface> { template class sentinel { using Parent = std::conditional_t; - using Base = std::conditional_t; + using Base = maybe_const; public: sentinel() = default; @@ -265,10 +276,18 @@ class transform_view : public view_interface> { return x.current_ == y.end_; } + friend constexpr bool operator==(const sentinel& y, const transform_view::iterator& x) { + return x == y; + } + friend constexpr bool operator!=(const transform_view::iterator& x, const sentinel& y) { return !(x == y); } + friend constexpr bool operator!=(const sentinel& y, const transform_view::iterator& x) { + return !(x == y); + } + template, iterator_t>::value, int> = 0> friend constexpr range_difference_t operator-(const iterator& x, const sentinel& y) { diff --git a/include/vccc/__ranges/views/views.hpp b/include/vccc/__ranges/views/views.hpp index b84d7f64..f17def2f 100644 --- a/include/vccc/__ranges/views/views.hpp +++ b/include/vccc/__ranges/views/views.hpp @@ -48,5 +48,9 @@ #include "vccc/__ranges/views/transform.hpp" #include "vccc/__ranges/views/transform_view.hpp" #include "vccc/__ranges/views/values_view.hpp" +#include "vccc/__ranges/views/zip_view.hpp" +#include "vccc/__ranges/views/zip.hpp" +#include "vccc/__ranges/views/zip_transform_view.hpp" +#include "vccc/__ranges/views/zip_transform.hpp" #endif // VCCC_RANGES_VIEWS_VIEWS_HPP_ diff --git a/include/vccc/__ranges/views/zip.hpp b/include/vccc/__ranges/views/zip.hpp new file mode 100644 index 00000000..7efc6f01 --- /dev/null +++ b/include/vccc/__ranges/views/zip.hpp @@ -0,0 +1,50 @@ +// +// Created by YongGyu Lee on 4/9/24. +// + +#ifndef VCCC_RANGES_VIEWS_ZIP_HPP_ +#define VCCC_RANGES_VIEWS_ZIP_HPP_ + +#include +#include + +#include "vccc/__core/decay_copy.hpp" +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__ranges/viewable_range.hpp" +#include "vccc/__ranges/views/all.hpp" +#include "vccc/__ranges/views/empty_view.hpp" +#include "vccc/__ranges/views/zip_view.hpp" +#include "vccc/__type_traits/conjunction.hpp" + +namespace vccc { +namespace ranges { +namespace views { +namespace detail { + +struct zip_niebloid { + constexpr auto operator()() const { + return vccc_decay_copy(views::empty>); + } + + template... + >::value, int> = 0> + constexpr auto operator()(Rs&&... rs) const { + return ranges::zip_view...>(rs...); + } +}; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::zip_niebloid zip{}; + +/// @} + +} // namespace views +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_ZIP_HPP_ diff --git a/include/vccc/__ranges/views/zip_transform.hpp b/include/vccc/__ranges/views/zip_transform.hpp new file mode 100644 index 00000000..8d9d082b --- /dev/null +++ b/include/vccc/__ranges/views/zip_transform.hpp @@ -0,0 +1,66 @@ +// +// Created by YongGyu Lee on 4/11/24. +// + +#ifndef VCCC_RANGES_VIEWS_ZIP_TRANSFORM_HPP_ +#define VCCC_RANGES_VIEWS_ZIP_TRANSFORM_HPP_ + +#include + +#include "vccc/__concepts/copy_constructible.hpp" +#include "vccc/__concepts/invocable.hpp" +#include "vccc/__core/decay_copy.hpp" +#include "vccc/__core/inline_or_static.hpp" +#include "vccc/__ranges/views/zip_transform_view.hpp" +#include "vccc/__ranges/range_adaptor.hpp" +#include "vccc/__ranges/range_adaptor_closure.hpp" +#include "vccc/__ranges/views/empty_view.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/is_invocable.hpp" +#include "vccc/__type_traits/is_referenceable.hpp" + +namespace vccc { +namespace ranges { +namespace views { +namespace detail { + +struct zip_transform_niebloid { + private: + template, is_referencable>::value /* false */> + struct check : std::false_type {}; + + template + struct check + : conjunction< + regular_invocable, + std::is_object> + > {}; + + public: + template>::value, int> = 0> + constexpr auto operator()(F&& f) const { + using FD = std::decay_t; + + return ((void)f, vccc_decay_copy(views::empty>>)); + } + + template + constexpr auto operator()(F&& f, Rs&&... rs) const { + return zip_transform_view, views::all_t...>(std::forward(f), std::forward(rs)...); + } +}; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +VCCC_INLINE_OR_STATIC constexpr detail::zip_transform_niebloid zip_transform{}; + +/// @} + +} // namespace views +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_ZIP_TRANSFORM_HPP_ diff --git a/include/vccc/__ranges/views/zip_transform_view.hpp b/include/vccc/__ranges/views/zip_transform_view.hpp new file mode 100644 index 00000000..a1873aca --- /dev/null +++ b/include/vccc/__ranges/views/zip_transform_view.hpp @@ -0,0 +1,419 @@ +// +// Created by YongGyu Lee on 4/9/24. +// + +#ifndef VCCC_RANGES_VIEWS_ZIP_TRANSFORM_VIEW_HPP_ +#define VCCC_RANGES_VIEWS_ZIP_TRANSFORM_VIEW_HPP_ + +#include +#include +#include + +#include "vccc/__compare/three_way_comparable.hpp" +#include "vccc/__concepts/derived_from.hpp" +#include "vccc/__concepts/equality_comparable.hpp" +#include "vccc/__concepts/invocable.hpp" +#include "vccc/__concepts/move_constructible.hpp" +#include "vccc/__concepts/move_constructible.hpp" +#include "vccc/__iterator/iterator_tag.hpp" +#include "vccc/__iterator/iterator_traits/cxx20_iterator_traits.hpp" +#include "vccc/__iterator/sized_sentinel_for.hpp" +#include "vccc/__ranges/bidirectional_range.hpp" +#include "vccc/__ranges/forward_range.hpp" +#include "vccc/__ranges/input_range.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__ranges/movable_box.hpp" +#include "vccc/__ranges/random_access_range.hpp" +#include "vccc/__ranges/range.hpp" +#include "vccc/__ranges/range_difference_t.hpp" +#include "vccc/__ranges/range_reference_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/zip_view.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/is_invocable.hpp" +#include "vccc/__type_traits/is_referenceable.hpp" +#include "vccc/__type_traits/maybe_const.hpp" +#include "vccc/__type_traits/negation.hpp" +#include "vccc/__utility/cxx20_rel_ops.hpp" +#include "vccc/__utility/type_sequence.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +template::value /* false */> +struct zip_transform_view_iterator_category { +#if __cplusplus < 202002L + using iterator_category = iterator_ignore; +#endif +}; + +template +struct zip_transform_view_iterator_category, true> { + private: + using MF = maybe_const; + template + using IC = typename cxx20_iterator_traits >>::iterator_category; + + template + using POT_derived_from = conjunction...>; + + public: + using iterator_category = + std::conditional_t< + negation>...> >>::value, input_iterator_tag, + std::conditional_t< + POT_derived_from::value, random_access_iterator_tag, + std::conditional_t< + POT_derived_from::value, bidirectional_iterator_tag, + std::conditional_t< + POT_derived_from::value, forward_iterator_tag, + input_iterator_tag + >>>>; +}; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +template +class zip_transform_view : public view_interface> { + public: + static_assert(move_constructible::value, "Constraints not satisfied"); + static_assert(conjunction...>::value, "Constraints not satisfied"); + static_assert(conjunction...>::value, "Constraints not satisfied"); + static_assert(sizeof...(Views) > 0, "Constraints not satisfied"); + static_assert(std::is_object::value, "Constraints not satisfied"); + static_assert(regular_invocable...>::value, "Constraints not satisfied"); + static_assert(is_referencable...>>::value, "Constraints not satisfied"); + + using tuple_index_sequence = std::index_sequence_for; + + template class sentinel; + template class iterator; + + private: + using InnerView = zip_view; + template using ziperator = iterator_t>; + template using zentinel = sentinel_t>; + + + public: + template + class iterator + : public detail::zip_transform_view_iterator_category< + Const, + InnerView, + F, + type_sequence> + { + using Parent = maybe_const; + using Base = maybe_const; + + friend class iterator; + friend class sentinel; + friend class sentinel; + friend class zip_transform_view; + + struct deref_fn { + private: + struct impl { + template + decltype(auto) operator()(const F& f, const Tuple& t, std::index_sequence) + noexcept(noexcept(vccc::invoke(f, std::get(t)...))) + { + return vccc::invoke(f, std::get(t)...); + } + }; + + public: + template + decltype(auto) operator()(const F& f, const Tuple& t) + noexcept(noexcept(vccc::invoke(impl{}, f, t, tuple_index_sequence{}))) + { + return impl{}(f, t, tuple_index_sequence{}); + } + + }; + + public: + + using iterator_concept = typename ziperator::iterator_concept; + using value_type = std::conditional_t...>>, + remove_cvref_t...>>>; + using difference_type = range_difference_t; + +#if __cplusplus < 202002L + using pointer = void; + using reference = invoke_result_t&>())>; +#endif + + iterator() = default; + + template, + convertible_to, ziperator> + >::value, int> = 0> + constexpr iterator(iterator i) + : parent_(std::move(i.parent_)), inner_(std::move(i.inner_)) {} + + constexpr decltype(auto) operator*() const + noexcept(noexcept(vccc::invoke(deref_fn{}, *parent_->fun_, *inner_))) + { + return deref_fn{}(*parent_->fun_, *inner_); + } + + template::value, int> = 0> + constexpr decltype(auto) operator[](difference_type n) const { + return vccc::apply( + [&](const auto&... iters) -> decltype(auto) { + return vccc::invoke(*parent_->fun_, iters[iter_difference_t>(n)]...); + } + ); + } + + constexpr iterator& operator++() { + ++inner_; + return *this; + } + + template::value, int> = 0> + constexpr void operator++(int) { + ++*this; + } + + template::value, int> = 0> + constexpr iterator operator++(int) { + auto tmp = *this; + ++*this; + return tmp; + } + + template::value, int> = 0> + constexpr iterator& operator--() { + --inner_; + return *this; + } + + template::value, int> = 0> + constexpr iterator operator--(int) { + auto tmp = *this; + --*this; + return tmp; + } + + template::value, int> = 0> + constexpr iterator& operator+=(difference_type n) { + inner_ += n; + return *this; + } + + template::value, int> = 0> + constexpr iterator& operator-=(difference_type n) { + inner_ -= n; + return *this; + } + + template, std::enable_if_t::value, int> = 0> + friend constexpr bool operator==(const iterator& x, const iterator& y) { + return x.inner_ == y.inner_; + } + + template, std::enable_if_t::value, int> = 0> + friend constexpr bool operator!=(const iterator& x, const iterator& y) { + return !(x.inner_ == y.inner_); + } + + template, std::enable_if_t, + unstable_three_way_comparable + >::value, int> = 0> + friend constexpr bool operator<(const iterator& x, const iterator& y) { + return x.inner_ < y.inner_; + } + + template, std::enable_if_t, + unstable_three_way_comparable + >::value, int> = 0> + friend constexpr bool operator<=(const iterator& x, const iterator& y) { + using namespace vccc::rel_ops; + return x <= y; + } + + template, std::enable_if_t, + unstable_three_way_comparable + >::value, int> = 0> + friend constexpr bool operator>(const iterator& x, const iterator& y) { + using namespace vccc::rel_ops; + return x > y; + } + + template, std::enable_if_t, + unstable_three_way_comparable + >::value, int> = 0> + friend constexpr bool operator>=(const iterator& x, const iterator& y) { + using namespace vccc::rel_ops; + return x >= y; + } + + template::value, int> = 0> + friend constexpr iterator operator+(const iterator& i, difference_type n) { + return iterator(*i.parent_, i.inner_ + n); + } + + template::value, int> = 0> + friend constexpr iterator operator+(difference_type n, const iterator& i) { + return iterator(*i.parent_, i.inner_ + n); + } + + template::value, int> = 0> + friend constexpr iterator operator-(const iterator& i, difference_type n) { + return iterator(*i.parent_, i.inner_ - n); + } + + template, std::enable_if_t::value, int> = 0> + friend constexpr difference_type operator-(const iterator& i, const iterator& j) { + return i.inner_ - j.inner_; + } + + private: + VCCC_CONSTEXPR_AFTER_CXX17 iterator(Parent& parent, ziperator inner) + : parent_(std::addressof(parent)), inner_(std::move(inner)) {} + + Parent* parent_{}; + ziperator inner_{}; + }; + + template + class sentinel { + friend class sentinel; + friend class zip_transform_view; + + public: + sentinel() = default; + + template, + convertible_to, zentinel> + >::value, int> = 0> + constexpr sentinel(sentinel i) + : inner_(std::move(i.inner_)) {} + + template, ziperator>::value, int> = 0> + friend constexpr bool operator==(const iterator& x, const sentinel& y) { + return y.equal_to(x); + } + + template, ziperator>::value, int> = 0> + friend constexpr bool operator==(const sentinel& y, const iterator& x) { + return x == y; + } + + template, ziperator>::value, int> = 0> + friend constexpr bool operator!=(const iterator& x, const sentinel& y) { + return !(x == y); + } + + template, ziperator>::value, int> = 0> + friend constexpr bool operator!=(const sentinel& y, const iterator& x) { + return !(x == y); + } + + template, ziperator>::value, int> = 0> + friend constexpr range_difference_t> + operator-(const iterator& x, const sentinel& y) { + return x.inner_ - y.inner_; + } + + template, ziperator>::value, int> = 0> + friend constexpr range_difference_t> + operator-(const sentinel& y, const iterator& x) { + return y.inner_ - x.inner_; + } + + private: + constexpr explicit sentinel(zentinel inner) + : inner_(std::move(inner)) {} + + template + constexpr bool equal_to(const iterator& x) const { + return x.inner_ == inner_; + } + + zentinel inner_{}; + }; + + zip_transform_view() = default; + + constexpr zip_transform_view(F fun, Views... views) + : fun_(std::move(fun)), zip_(std::move(views)...) {} + + constexpr iterator begin() { + return iterator(*this, zip_.begin()); + } + + template, + range> + >::value, int> = 0> + constexpr iterator begin() const { + return iterator(*this, zip_.begin()); + } + + constexpr auto end() { + return end_impl(*this, common_range{}); + } + + constexpr auto end() const { + return end_impl(*this, common_range{}); + } + + template, + sized_range + >::value, int> = 0> + constexpr auto size() { + return zip_.size(); + } + + template, + sized_range + >::value, int> = 0> + constexpr auto size() const { + return zip_.size(); + } + + private: + template + static constexpr iterator end_impl(Self&& self, std::true_type /* common_range */) { + return iterator(self, self.zip_.end()); + } + + template + static constexpr sentinel end_impl(Self&& self, std::false_type /* common_range */) { + return sentinel(self.zip_.end()); + } + + movable_box fun_{}; + InnerView zip_{}; +}; + +#if __cplusplus >= 201703L + +template +zip_transform_view(F, Rs&&...) -> zip_transform_view...>; + +#endif + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_ZIP_TRANSFORM_VIEW_HPP_ diff --git a/include/vccc/__ranges/views/zip_view.hpp b/include/vccc/__ranges/views/zip_view.hpp new file mode 100644 index 00000000..f5b24bed --- /dev/null +++ b/include/vccc/__ranges/views/zip_view.hpp @@ -0,0 +1,558 @@ +// +// Created by YongGyu Lee on 4/8/24. +// + +#ifndef VCCC_RANGES_VIEWS_ZIP_VIEW_HPP_ +#define VCCC_RANGES_VIEWS_ZIP_VIEW_HPP_ + +#include +#include +#include +#include + +#include "vccc/__algorithm/ranges/min.hpp" +#include "vccc/__concepts/convertible_to.hpp" +#include "vccc/__concepts/equality_comparable.hpp" +#include "vccc/__iterator/iterator_tag.hpp" +#include "vccc/__iterator/iter_move.hpp" +#include "vccc/__iterator/iter_swap.hpp" +#include "vccc/__iterator/sentinel_for.hpp" +#include "vccc/__iterator/sized_sentinel_for.hpp" +#include "vccc/__ranges/begin.hpp" +#include "vccc/__ranges/bidirectional_range.hpp" +#include "vccc/__ranges/common_range.hpp" +#include "vccc/__ranges/forward_range.hpp" +#include "vccc/__ranges/input_range.hpp" +#include "vccc/__ranges/iterator_t.hpp" +#include "vccc/__ranges/random_access_range.hpp" +#include "vccc/__ranges/range_difference_t.hpp" +#include "vccc/__ranges/range_rvalue_reference_t.hpp" +#include "vccc/__ranges/range_value_t.hpp" +#include "vccc/__ranges/sentinel_t.hpp" +#include "vccc/__ranges/simple_view.hpp" +#include "vccc/__ranges/size.hpp" +#include "vccc/__ranges/view.hpp" +#include "vccc/__ranges/view_interface.hpp" +#include "vccc/__ranges/views/all.hpp" +#include "vccc/__tuple/apply.hpp" +#include "vccc/__tuple/tuple_fold.hpp" +#include "vccc/__tuple/tuple_for_each.hpp" +#include "vccc/__tuple/tuple_transform.hpp" +#include "vccc/__type_traits/bool_constant.hpp" +#include "vccc/__type_traits/common_type.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/disjunction.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" +#include "vccc/__utility/in_place.hpp" + +namespace vccc { +namespace ranges { +namespace detail { + +template +struct zip_view_iterator_category { + using iterator_category = input_iterator_tag; +}; + +template<> +struct zip_view_iterator_category { +#if __cplusplus < 202002L + using iterator_category = iterator_ignore; +#endif +}; + +template +struct min_tuple_distance_fn { + template + R operator()(const T1& t1, const T2& t2) const { + static_assert(std::tuple_size>::value == + std::tuple_size>::value, "Size doesn't match"); + + return call(t1, t2, std::make_index_sequence>::value>{}); + } + + private: + template + R call(const T1& t1, const T2& t2, std::index_sequence) const { + return (ranges::min)({R(std::get(t1) - std::get(t2))...}); + } +}; + +template +struct zip_is_common + : disjunction< + conjunction< + bool_constant, + common_range... + >, + conjunction< + negation< + conjunction...> + >, + common_range... + >, + conjunction< + random_access_range..., + sized_range... + > + > {}; + +} // namespace detail + +/// @addtogroup ranges +/// @{ + +template +class zip_view : public view_interface> { + static constexpr std::size_t kViewCount = sizeof...(Views); + using tuple_index_sequence = std::index_sequence_for; + + public: + static_assert(sizeof...(Views) > 0, "Constraints not satisfied"); + static_assert(conjunction...>::value, "Constraints not satisfied"); + static_assert(conjunction...>::value, "Constraints not satisfied"); + + template class iterator; + template class sentinel; + + + template + class iterator : public detail::zip_view_iterator_category>...>::value> { + using all_forward = conjunction>...>; + using all_bidirectional = conjunction>...>; + using all_random_access = conjunction>...>; + + friend class iterator; + friend class sentinel; + friend class sentinel; + friend class zip_view; + + struct tuple_deref_fn { + template + constexpr decltype(auto) operator()(I& i) const { + return *i; + } + }; + + public: + using iterator_concept = + std::conditional_t< + all_random_access::value, random_access_iterator_tag, + std::conditional_t< + all_bidirectional::value, bidirectional_iterator_tag, + std::conditional_t< + all_forward::value, forward_iterator_tag, + input_iterator_tag + >>>; + using value_type = std::tuple...>; + using difference_type = common_type_t>...>; + +#if __cplusplus < 202002L + using pointer = void; + using reference = decltype(vccc::tuple_transform( + std::declval>...>&>(), + std::declval() + )); +#endif + + iterator() = default; + + template, + convertible_to, iterator_t>>... + >::value, int> = 0> + constexpr iterator(iterator i) + : current_(std::move(i.current_)) {} + + constexpr decltype(auto) operator*() const { + return vccc::tuple_transform(current_, [](auto& i) -> decltype(auto) { return *i; }); + } + + + template, + all_random_access + >::value, int> = 0> + constexpr decltype(auto) operator[](difference_type n) const { + return vccc::tuple_transform( + current_, + [&](auto& i) -> decltype(auto) { + static_assert(std::is_lvalue_reference::value, "Invalid type"); + using I = remove_cvref_t; + return i[iter_difference_t(n)]; + } + ); + } + + constexpr iterator& operator++() { + vccc::tuple_for_each(current_, [](auto& i) { ++i; }); + return *this; + } + + template = 0> + constexpr void operator++(int) { + ++*this; + } + + template = 0> + constexpr iterator operator++(int) { + auto tmp = *this; + ++*this; + return tmp; + } + + template = 0> + constexpr iterator& operator--() { + vccc::tuple_for_each(current_, [](auto& i) { --i; }); + } + + template = 0> + constexpr iterator operator--(int) { + auto tmp = *this; + --*this; + return tmp; + } + + template = 0> + constexpr iterator& operator+=(difference_type n) { + vccc::tuple_for_each(current_, [&](auto& i) { + static_assert(std::is_lvalue_reference::value, "Invalid type"); + using I = remove_cvref_t; + i += iter_difference_t(n); + }); + return *this; + } + + template = 0> + constexpr iterator& operator-=(difference_type n) { + vccc::tuple_for_each(current_, [&](auto& i) { + static_assert(std::is_lvalue_reference::value, "Invalid type"); + using I = remove_cvref_t; + i -= iter_difference_t(n); + }); + return *this; + } + + template, + equality_comparable>>... + >::value, int> = 0> + friend constexpr bool operator==(const iterator& x, const iterator& y) { + return x.equal(y); + } + + template, + equality_comparable>>... + >::value, int> = 0> + friend constexpr bool operator!=(const iterator& x, const iterator& y) { + return !(x == y); + } + + template = 0> + friend constexpr bool operator<(const iterator& x, const iterator& y) { + return x.current_ < y.current_; + } + + template = 0> + friend constexpr bool operator<=(const iterator& x, const iterator& y) { + using namespace rel_ops; + return x.current_ <= y.current_; + } + + template = 0> + friend constexpr bool operator>(const iterator& x, const iterator& y) { + using namespace rel_ops; + return x.current_ > y.current_; + } + + template = 0> + friend constexpr bool operator>=(const iterator& x, const iterator& y) { + using namespace rel_ops; + return x.current_ >= y.current_; + } + + template = 0> + friend constexpr iterator operator+(const iterator& i, difference_type n) { + auto r = i; + r += n; + return r; + } + + template = 0> + friend constexpr iterator operator+(difference_type n, const iterator& i) { + auto r = i; + r += n; + return r; + } + + template = 0> + friend constexpr iterator operator-(const iterator& i, difference_type n) { + auto r = i; + r -= n; + return r; + } + + template, + sized_sentinel_for>, + iterator_t>> + ... + >::value, int> = 0> + friend constexpr difference_type operator-(const iterator& i, const iterator& j) { + return detail::min_tuple_distance_fn{}(i.current_, j.current_); + } + + friend constexpr auto iter_move(const iterator& i) + noexcept(conjunction< + bool_constant>&>() + ) + )>..., + std::is_nothrow_move_constructible< + range_rvalue_reference_t> + >... + >::value) + { + return vccc::tuple_transform(i.current_, ranges::iter_move); + } + + template>>...>, + std::enable_if_t = 0> + friend constexpr void iter_swap(const iterator& x, const iterator& y) + noexcept(conjunction< + bool_constant>&>(), + std::declval>&>() + ))>... + >::value) + { + x.iter_swap_impl(y, tuple_index_sequence{}); + } + + private: + template + constexpr explicit iterator(in_place_t, Tuple&& tup) + : current_(std::forward(tup)) {} + + constexpr bool equal(const iterator& other) const { + return equal_1(other, all_bidirectional{}); + } + + constexpr bool equal_1(const iterator& other, std::true_type /* all_bidirectional */) const { + return current_ == other.current_; + } + + constexpr bool equal_1(const iterator& other, std::false_type /* all_bidirectional */) const { + return equal_2(other, in_place_index_t<0>{}); + } + + template = 0> + constexpr bool equal_2(const OtherTuple& t, in_place_index_t) const { + return bool(std::get(current_) == std::get(t)) + ? true + : equal_2(t, in_place_index_t{}); + } + + template + constexpr bool equal_2(const OtherTuple&, in_place_index_t) const { + return false; + } + + template + constexpr void iter_swap_impl(const iterator& other, std::index_sequence) const { + int dummy[] = { + (ranges::iter_swap(std::get(current_), std::get(other.current_)), 0)... + }; + (void)dummy; + } + + std::tuple>...> current_{}; + }; + + template + class sentinel { + friend class zip_view; + + public: + sentinel() = default; + + template, + convertible_to, sentinel_t>>... + >::value, int> = 0> + constexpr sentinel(sentinel i) + : end_(std::move(i.end_)) {} + + template>, + iterator_t> + >... + >::value, int> = 0> + friend constexpr bool operator==(const iterator& x, const sentinel& y) { + return y.is_equal(x); + } + + template>, + iterator_t> + >... + >::value, int> = 0> + friend constexpr bool operator==(const sentinel& y, const iterator& x) { + return x == y; + } + + template>, + iterator_t> + >... + >::value, int> = 0> + friend constexpr bool operator!=(const iterator& x, const sentinel& y) { + return !(x == y); + } + + template>, + iterator_t> + >... + >::value, int> = 0> + friend constexpr bool operator!=(const sentinel& y, const iterator& x) { + return !(x == y); + } + + template>, + iterator_t> + >... + >::value, int> = 0> + friend constexpr common_type_t>...> + operator-(const iterator& x, const sentinel& y) { + using R = common_type_t>...>; + return detail::min_tuple_distance_fn{}(x.current_, y.end_); + } + + template>, + iterator_t> + >... + >::value, int> = 0> + friend constexpr common_type_t>...> + operator-(const sentinel& y, const iterator& x) { + return -(x - y); + } + + private: + template + constexpr explicit sentinel(in_place_t, Tuple&& tup) + : end_(std::forward(tup)) {} + + template + constexpr bool is_equal(const iterator& i) const { + return i.equal_2(end_, in_place_index_t<0>{}); + } + + std::tuple>...> end_{}; + }; + + zip_view() = default; + + constexpr zip_view(Views... views) + : views_(std::move(views)...) {} + + template, + negation< + simple_view + >... + >::value, int> = 0> + constexpr auto begin() { + return iterator(in_place, vccc::tuple_transform(views_, ranges::begin)); + } + + template, + range... + >::value, int> = 0> + constexpr auto begin() const { + return iterator(in_place, vccc::tuple_transform(views_, ranges::begin)); + } + + template, + negation< + simple_view + >... + >::value, int> = 0> + constexpr auto end() { + return end_impl(*this, detail::zip_is_common{}, conjunction...>{}); + } + + template, + range... + >::value, int> = 0> + constexpr auto end() const { + return end_impl(*this, detail::zip_is_common{}, conjunction...>{}); + } + + template, + sized_range... + >::value, int> = 0> + constexpr auto size() { + return vccc::apply( + [](auto... sizes) { + using CT = std::make_unsigned_t>; + return (ranges::min)({CT(sizes)...}); + }, + vccc::tuple_transform(views_, ranges::size) + ); + } + + template, + sized_range... + >::value, int> = 0> + constexpr auto size() const { + return vccc::apply( + [](auto... sizes) { + using CT = std::make_unsigned_t>; + return (ranges::min)({CT(sizes)...}); + }, + vccc::tuple_transform(views_, ranges::size) + ); + } + + private: + template + static constexpr auto end_impl(Self&& self, std::false_type /* zip_is_common */, Any) { + return sentinel{in_place, vccc::tuple_transform(self.views_, ranges::end)}; + } + + template + static constexpr auto end_impl(Self&& self, std::true_type /* zip_is_common */, std::true_type /* random_access_range */) { + return self.begin() + iter_difference_t>(self.size()); + } + + template + static constexpr auto end_impl(Self&& self, std::true_type /* zip_is_common */, std::false_type /* random_access_range */) { + return iterator(in_place, vccc::tuple_transform(self.views_, ranges::end)); + } + + std::tuple views_{}; +}; + +#if __cplusplus >= 201703L + +template +zip_view(Rs&&...) -> zip_view...>; + +#endif + +/// @} + +} // namespace ranges +} // namespace vccc + +#endif // VCCC_RANGES_VIEWS_ZIP_VIEW_HPP_ diff --git a/include/vccc/__span/dynamic_extent.hpp b/include/vccc/__span/dynamic_extent.hpp index d9f16240..f0d4f3c1 100644 --- a/include/vccc/__span/dynamic_extent.hpp +++ b/include/vccc/__span/dynamic_extent.hpp @@ -12,8 +12,13 @@ namespace vccc { +/// @addtogroup span +/// @{ + VCCC_INLINE_OR_STATIC constexpr std::size_t dynamic_extent = (std::numeric_limits::max)(); +/// @} + } // namespace vccc #endif // VCCC_SPAN_DYNAMIC_EXTENT_HPP diff --git a/include/vccc/__tuple/tuple_for_each.hpp b/include/vccc/__tuple/tuple_for_each.hpp new file mode 100644 index 00000000..bf8ead15 --- /dev/null +++ b/include/vccc/__tuple/tuple_for_each.hpp @@ -0,0 +1,99 @@ +// +// Created by YongGyu Lee on 4/9/24. +// + +#ifndef VCCC_TUPLE_TUPLE_FOR_EACH_HPP_ +#define VCCC_TUPLE_TUPLE_FOR_EACH_HPP_ + +#include +#include +#include +#include + +#include "vccc/__functional/invoke.hpp" +#include "vccc/__utility/in_place.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/copy_cvref.hpp" +#include "vccc/__type_traits/is_invocable.hpp" +#include "vccc/__type_traits/remove_cvref.hpp" + +namespace vccc { +namespace detail { + +template +using tuple_index_sequence = std::make_index_sequence>::value>; + +template +struct tuple_for_each_invocable_impl; + +template +struct tuple_for_each_invocable_impl> + : conjunction< + is_invocable(std::declval()))>... + > {}; + +template +struct tuple_for_each_invocable + : tuple_for_each_invocable_impl> {}; + +template +constexpr void tuple_for_each_impl(std::index_sequence, Tuple&& t, F&& f) { + int dummy[] = { + (vccc::invoke(f, std::get(std::forward(t))), 0)... + }; + (void)dummy; +} + +template +struct tuple_for_each_in_place_index_invocable_impl; + +template +struct tuple_for_each_in_place_index_invocable_impl> + : conjunction< + is_invocable(std::declval())), std::integral_constant>... + > {}; + +template +struct tuple_for_each_in_place_index_invocable + : tuple_for_each_in_place_index_invocable_impl> {}; + +template +constexpr void tuple_for_each_index_impl(std::index_sequence, Tuple&& t, F&& f) { + int dummy[] = { + (vccc::invoke(f, std::get(std::forward(t)), std::integral_constant{}), 0)... + }; + (void)dummy; +} + +} // namespace detail + +/// @addtogroup tuple +/// @{ + +// Invokes f(std::get(t)) for each i in [0, std::tuple_size) +template +constexpr std::enable_if_t::value> +tuple_for_each(Tuple&& t, F&& f) { + return vccc::detail::tuple_for_each_impl( + detail::tuple_index_sequence{}, + std::forward(t), + std::forward(f) + ); +} + +// Invokes f(std::get(t), std::integral_constant{}) for each i in [0, std::tuple_size) +template +constexpr std::enable_if_t::value> +tuple_for_each_index(Tuple&& t, F&& f) { + return vccc::detail::tuple_for_each_index_impl( + detail::tuple_index_sequence{}, + std::forward(t), + std::forward(f) + ); +} + +/// @} + +} // namespace vccc + +#endif // VCCC_TUPLE_TUPLE_FOR_EACH_HPP_ diff --git a/include/vccc/__tuple/tuple_transform.hpp b/include/vccc/__tuple/tuple_transform.hpp index 6cca494a..bcd12d32 100644 --- a/include/vccc/__tuple/tuple_transform.hpp +++ b/include/vccc/__tuple/tuple_transform.hpp @@ -9,13 +9,19 @@ #include #include "vccc/__functional/invoke.hpp" +#include "vccc/__type_traits/bool_constant.hpp" +#include "vccc/__type_traits/conjunction.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) { +constexpr auto tuple_transform_impl(Tuple&& t, F&& f, std::index_sequence) + noexcept(conjunction< + bool_constant(f), std::get(std::forward(t))))>... + >::value) +{ return std::tuple(f), std::get(std::forward(t))))...>( vccc::invoke(std::forward(f), std::get(std::forward(t)))...); } @@ -27,7 +33,15 @@ constexpr auto tuple_transform_impl(Tuple&& t, F&& f, std::index_sequence) /// @brief Constructs a new tuple with each elements transformed template -constexpr auto tuple_transform(Tuple&& t, F&& f) { +constexpr auto tuple_transform(Tuple&& t, F&& f) + noexcept(noexcept( + detail::tuple_transform_impl( + std::forward(t), + std::forward(f), + std::make_index_sequence>::value>{} + ) + )) +{ return detail::tuple_transform_impl( std::forward(t), std::forward(f), std::make_index_sequence>::value>{}); diff --git a/include/vccc/__type_traits/copy_template.hpp b/include/vccc/__type_traits/copy_template.hpp new file mode 100644 index 00000000..59dbb85f --- /dev/null +++ b/include/vccc/__type_traits/copy_template.hpp @@ -0,0 +1,30 @@ +// +// Created by YongGyu Lee on 5/16/24. +// + +#ifndef VCCC_TYPE_TRAITS_COPY_TEMPLATE_HPP_ +#define VCCC_TYPE_TRAITS_COPY_TEMPLATE_HPP_ + +#include "vccc/__type_traits/type_identity.hpp" + +namespace vccc { + +/// @addtogroup type_traits +/// @{ + +template class To, template class Proj = type_identity_t> +struct copy_template; + +template class From, typename... T, template class To, template class Proj> +struct copy_template, To, Proj> { + using type = To...>; +}; + +template class To, template class Proj = type_identity_t> +using copy_template_t = typename copy_template::type; + +/// @} + +} // namespace vccc + +#endif // VCCC_TYPE_TRAITS_COPY_TEMPLATE_HPP_ diff --git a/include/vccc/__type_traits/core/size.hpp b/include/vccc/__type_traits/core/size.hpp index 4194d046..a9028ed5 100644 --- a/include/vccc/__type_traits/core/size.hpp +++ b/include/vccc/__type_traits/core/size.hpp @@ -29,13 +29,15 @@ constexpr inline auto ssize(const C& c) -> common_type_t> { using R = common_type_t>; + static_assert(std::is_signed::value, "R must be signed integer"); return static_cast(c.size()); } -template +template constexpr inline std::ptrdiff_t ssize(const T (&array)[N]) noexcept { - return static_cast(N); + static_assert(std::is_signed::value, "R must be signed integer"); + return N; } } // namespace vccc diff --git a/include/vccc/__type_traits/has_operator_arrow.hpp b/include/vccc/__type_traits/has_operator_arrow.hpp index 38905996..c8722eda 100644 --- a/include/vccc/__type_traits/has_operator_arrow.hpp +++ b/include/vccc/__type_traits/has_operator_arrow.hpp @@ -11,12 +11,17 @@ namespace vccc { +/// @addtogroup type_traits +/// @{ + template struct has_operator_arrow : std::false_type {}; template struct has_operator_arrow().operator->())>> : std::true_type {}; +/// @} + } // namespace vccc #endif // VCCC_TYPE_TRAITS_HAS_OPERATOR_ARROW_HPP diff --git a/include/vccc/__type_traits/has_typename_difference_type.hpp b/include/vccc/__type_traits/has_typename_difference_type.hpp index 2a45cb2d..5655848c 100644 --- a/include/vccc/__type_traits/has_typename_difference_type.hpp +++ b/include/vccc/__type_traits/has_typename_difference_type.hpp @@ -11,12 +11,17 @@ namespace vccc { +/// @addtogroup type_traits +/// @{ + template struct has_typename_difference_type : std::false_type {}; template struct has_typename_difference_type> : std::true_type {}; +/// @} + } // namespace vccc #endif // VCCC_TYPE_TRAITS_HAS_TYPENAME_DIFFERENCE_TYPE_HPP_ diff --git a/include/vccc/__type_traits/has_typename_element_type.hpp b/include/vccc/__type_traits/has_typename_element_type.hpp index 124cb46d..b41b5ee4 100644 --- a/include/vccc/__type_traits/has_typename_element_type.hpp +++ b/include/vccc/__type_traits/has_typename_element_type.hpp @@ -11,12 +11,17 @@ namespace vccc { +/// @addtogroup type_traits +/// @{ + template struct has_typename_element_type : std::false_type {}; template struct has_typename_element_type> : std::true_type {}; +/// @} + } // namespace vccc #endif // VCCC_TYPE_TRAITS_HAS_TYPENAME_VALUE_TYPE_HPP_ diff --git a/include/vccc/__type_traits/has_typename_type.hpp b/include/vccc/__type_traits/has_typename_type.hpp index 6425032b..13428e08 100644 --- a/include/vccc/__type_traits/has_typename_type.hpp +++ b/include/vccc/__type_traits/has_typename_type.hpp @@ -11,12 +11,17 @@ namespace vccc { +/// @addtogroup type_traits +/// @{ + template struct has_typename_type : std::false_type {}; template struct has_typename_type> : std::true_type {}; +/// @} + } // namespace vccc #endif // VCCC_TYPE_TRAITS_HAS_TYPENAME_TYPE_HPP_ diff --git a/include/vccc/__type_traits/has_typename_value_type.hpp b/include/vccc/__type_traits/has_typename_value_type.hpp index 7efdece7..b257af9e 100644 --- a/include/vccc/__type_traits/has_typename_value_type.hpp +++ b/include/vccc/__type_traits/has_typename_value_type.hpp @@ -11,12 +11,17 @@ namespace vccc { +/// @addtogroup type_traits +/// @{ + template struct has_typename_value_type : std::false_type {}; template struct has_typename_value_type> : std::true_type {}; +/// @} + } // namespace vccc #endif // VCCC_TYPE_TRAITS_HAS_TYPENAME_VALUE_TYPE_HPP_ diff --git a/include/vccc/__type_traits/is_character.hpp b/include/vccc/__type_traits/is_character.hpp new file mode 100644 index 00000000..0b94169a --- /dev/null +++ b/include/vccc/__type_traits/is_character.hpp @@ -0,0 +1,50 @@ +// +// Created by YongGyu Lee on 5/8/24. +// + +#ifndef VCCC_TYPE_TRAITS_IS_CHARACTER_HPP_ +#define VCCC_TYPE_TRAITS_IS_CHARACTER_HPP_ + +#include + +#include "vccc/__config.h" + +namespace vccc { + +/// @addtogroup type_traits +/// @{ + +/** + * @brief Check if type is character type + * @tparam T + */ +template +struct is_character : std::false_type {}; + +#if VCCC_HAS_TYPE_CHAR +template<> struct is_character : std::true_type {}; +template<> struct is_character : std::true_type {}; +template<> struct is_character : std::true_type {}; +#endif // VCCC_HAS_TYPE_CHAR + +#if VCCC_HAS_TYPE_WCHAR_T +template<> struct is_character : std::true_type {}; +#endif // VCCC_HAS_TYPE_WCHAR_T + +#if VCCC_HAS_TYPE_CHAR16_T +template<> struct is_character : std::true_type {}; +#endif // VCCC_HAS_TYPE_CHAR16_T + +#if VCCC_HAS_TYPE_CHAR32_T +template<> struct is_character : std::true_type {}; +#endif // VCCC_HAS_TYPE_CHAR32_T + +#if __cplusplus >= 202002L && VCCC_HAS_TYPE_CHAR8_T_CXX20 +template<> struct is_character : std::true_type {}; +#endif // __cplusplus >= 202002L && VCCC_HAS_TYPE_CHAR8_T_CXX20 + +/// @} + +} // namespace vccc + +#endif // VCCC_TYPE_TRAITS_IS_CHARACTER_HPP_ diff --git a/include/vccc/__type_traits/is_complete.hpp b/include/vccc/__type_traits/is_complete.hpp index 0b1064d2..4725d09b 100644 --- a/include/vccc/__type_traits/is_complete.hpp +++ b/include/vccc/__type_traits/is_complete.hpp @@ -16,9 +16,14 @@ std::true_type is_complete_impl(T *); std::false_type is_complete_impl(...); } // namespace detail +/// @addtogroup type_traits +/// @{ + template using is_complete = decltype(detail::is_complete_impl(std::declval())); +/// @} + } // namespace vccc #endif // VCCC_TYPE_TRAITS_IS_COMPLETE_HPP_ diff --git a/include/vccc/__type_traits/is_range.hpp b/include/vccc/__type_traits/is_range.hpp index 871d9af7..a50d2ceb 100644 --- a/include/vccc/__type_traits/is_range.hpp +++ b/include/vccc/__type_traits/is_range.hpp @@ -12,13 +12,15 @@ namespace vccc { /** @addtogroup type_traits @{ @defgroup is_range is_range - @brief check if a type is range + @brief check if a type is range(deprecated) @} @addtogroup is_range @{ */ /** -@brief check if a type met range requirements +@brief check if a type met range requirements(deprecated) + +Use ranges::ranges instead */ template struct is_range : std::false_type {}; diff --git a/include/vccc/__type_traits/is_referenceable.hpp b/include/vccc/__type_traits/is_referenceable.hpp index f198daed..dafa14e5 100644 --- a/include/vccc/__type_traits/is_referenceable.hpp +++ b/include/vccc/__type_traits/is_referenceable.hpp @@ -11,12 +11,17 @@ namespace vccc { +/// @addtogroup type_traits +/// @{ + template struct is_referencable : std::false_type {}; template struct is_referencable> : std::true_type {}; +/// @} + } // namespace vccc #endif // VCCC_TYPE_TRAITS_IS_REFERENCEABLE_HPP diff --git a/include/vccc/__type_traits/is_swappable.hpp b/include/vccc/__type_traits/is_swappable.hpp index 5c6be848..a1ac78a4 100644 --- a/include/vccc/__type_traits/is_swappable.hpp +++ b/include/vccc/__type_traits/is_swappable.hpp @@ -16,6 +16,9 @@ namespace vccc { +/// @addtogroup type_traits +/// @{ + template struct is_swappable; template struct is_nothrow_swappable; @@ -121,6 +124,8 @@ struct is_nothrow_swappable_with : internal::is_nothrow_swappable_with_impl struct is_nothrow_swappable : is_nothrow_swappable_with {}; +/// @} + } // namespace vccc diff --git a/include/vccc/__type_traits/is_tuple_like.hpp b/include/vccc/__type_traits/is_tuple_like.hpp index a241aabe..55853448 100644 --- a/include/vccc/__type_traits/is_tuple_like.hpp +++ b/include/vccc/__type_traits/is_tuple_like.hpp @@ -10,12 +10,18 @@ namespace vccc { +/// @addtogroup type_traits +/// @{ + +/// @brief Check if type is tuple-like(deprecated. Use \ref tuple_like instead) template struct is_tuple_like : std::false_type {}; template struct is_tuple_like::value)>> : std::true_type {}; +/// @} + } // namespace vccc # endif // VCCC_TYPE_TRAITS_IS_TUPLE_LIKE_HPP diff --git a/include/vccc/__type_traits/iterable.hpp b/include/vccc/__type_traits/iterable.hpp index d05bb42e..7573bb80 100644 --- a/include/vccc/__type_traits/iterable.hpp +++ b/include/vccc/__type_traits/iterable.hpp @@ -13,9 +13,10 @@ namespace vccc { @addtogroup type_traits @{ @defgroup is_iterator is_iterator - @brief check if a type is a iterable type + @brief check if a type is a iterable type(deprecated) std::iterator or pointer type + This is deprecated. Use \ref input_iterator instead @} @addtogroup is_iterator diff --git a/include/vccc/__type_traits/maybe_const.hpp b/include/vccc/__type_traits/maybe_const.hpp index 7e8e397c..41fcc8e1 100644 --- a/include/vccc/__type_traits/maybe_const.hpp +++ b/include/vccc/__type_traits/maybe_const.hpp @@ -9,9 +9,14 @@ namespace vccc { +/// @addtogroup type_traits +/// @{ + template using maybe_const = std::conditional_t; +/// @} + } // namespace vccc #endif // VCCC_TYPE_TRAITS_MAYBE_CONST_HPP diff --git a/include/vccc/__type_traits/simple_common_reference.hpp b/include/vccc/__type_traits/simple_common_reference.hpp index 56cffba9..bf6e2cf5 100644 --- a/include/vccc/__type_traits/simple_common_reference.hpp +++ b/include/vccc/__type_traits/simple_common_reference.hpp @@ -87,6 +87,9 @@ struct simple_common_reference_mixed_ref {}; } // namespace impl +/// @addtogroup type_traits +/// @{ + template struct simple_common_reference {}; // no simple common reference type @@ -105,6 +108,8 @@ struct simple_common_reference template struct simple_common_reference : simple_common_reference {}; +/// @} + } // namespace vccc #endif // VCCC_TYPE_TRAITS_SIMPLE_COMMON_REFERENCE_HPP_ diff --git a/include/vccc/__utility/cmp.hpp b/include/vccc/__utility/cmp.hpp new file mode 100644 index 00000000..6ab67747 --- /dev/null +++ b/include/vccc/__utility/cmp.hpp @@ -0,0 +1,99 @@ +// +// Created by YongGyu Lee on 5/8/24. +// + +#ifndef VCCC_UTILITY_CMP_HPP_ +#define VCCC_UTILITY_CMP_HPP_ + +#include + +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/is_character.hpp" +#include "vccc/__type_traits/negation.hpp" +#include "vccc/__type_traits/remove_cvref.hpp" + +namespace vccc { +namespace detail { + +template +constexpr bool cmp_equal_impl(T t, U u, SameSignity...) noexcept { + return t == u; +} + +template +constexpr bool cmp_equal_impl(T t, U u, std::true_type, std::false_type) noexcept { + return t >= 0 && std::make_unsigned_t(t) == u; +} + +template +constexpr bool cmp_equal_impl(T t, U u, std::false_type, std::true_type) noexcept { + return u >= 0 && std::make_unsigned_t(u) == t; +} + +template +constexpr bool cmp_less_impl(T t, U u, SameSignity...) noexcept { + return t < u; +} + +template +constexpr bool cmp_less_impl(T t, U u, std::true_type, std::false_type) noexcept { + return t < 0 || std::make_unsigned_t(t) < u; +} + +template +constexpr bool cmp_less_impl(T t, U u, std::false_type, std::true_type) noexcept { + return u >= 0 && t < std::make_unsigned_t(u); +} + +template +using cmp_requires_one = + conjunction< + std::is_integral, + negation>, + negation> + >; +template +using cmp_requires = conjunction>, cmp_requires_one>>; + +} // namespace detail + +/// @addtogroup utility +/// @{ + +template +constexpr bool cmp_equal(T t, U u) noexcept { + static_assert(detail::cmp_requires::value, "Both values must be integral, not a character type and not bool"); + return vccc::detail::cmp_equal_impl(t, u, std::is_signed{}, std::is_signed{}); +} + +template +constexpr bool cmp_not_equal(T t, U u) noexcept { + return !vccc::cmp_equal(t, u); +} + +template +constexpr bool cmp_less(T t, U u) noexcept { + static_assert(detail::cmp_requires::value, "Both values must be integral, not a character type and not bool"); + return vccc::detail::cmp_less_impl(t, u, std::is_signed{}, std::is_signed{}); +} + +template +constexpr bool cmp_greater(T t, U u) noexcept { + return vccc::cmp_less(u, t); +} + +template +constexpr bool cmp_less_equal(T t, U u) noexcept { + return !vccc::cmp_less(u, t); +} + +template +constexpr bool cmp_greater_equal(T t, U u) noexcept { + return !vccc::cmp_less(t, u); +} + +/// @} + +} // namespace vccc + +#endif // VCCC_UTILITY_CMP_HPP_ diff --git a/include/vccc/__utility/cxx20_rel_ops.hpp b/include/vccc/__utility/cxx20_rel_ops.hpp index 0d6d195f..ff3517a8 100644 --- a/include/vccc/__utility/cxx20_rel_ops.hpp +++ b/include/vccc/__utility/cxx20_rel_ops.hpp @@ -127,6 +127,9 @@ int main() { */ /// @brief synthesized from `U == T` + +#if __cplusplus < 202002L + template>, detail::has_operator_equal_2 @@ -135,6 +138,8 @@ constexpr bool operator==(const T& a, const U& b) noexcept(noexcept(b == a)) { return b == a; } +#endif // __cplusplus < 202002L + namespace detail { struct is_equality_comparable_impl { diff --git a/include/vccc/__utility/in_range.hpp b/include/vccc/__utility/in_range.hpp new file mode 100644 index 00000000..0064f573 --- /dev/null +++ b/include/vccc/__utility/in_range.hpp @@ -0,0 +1,27 @@ +// +// Created by YongGyu Lee on 5/8/24. +// + +#ifndef VCCC_UTILITY_IN_RANGE_HPP_ +#define VCCC_UTILITY_IN_RANGE_HPP_ + +#include + +#include "vccc/__utility/cmp.hpp" + +namespace vccc { + +/// @addtogroup utility +/// @{ + +template +constexpr bool in_range(T t) noexcept { + return vccc::cmp_greater_equal(t, (std::numeric_limits::min)()) && + vccc::cmp_less_equal(t, (std::numeric_limits::max)()); +} + +/// @} + +} // namespace vccc + +#endif // VCCC_UTILITY_IN_RANGE_HPP_ diff --git a/include/vccc/__utility/sequence_for_each.hpp b/include/vccc/__utility/sequence_for_each.hpp new file mode 100644 index 00000000..c1ea4832 --- /dev/null +++ b/include/vccc/__utility/sequence_for_each.hpp @@ -0,0 +1,62 @@ +// +// Created by YongGyu Lee on 2024. 5. 17. +// + +#ifndef VCCC_UTILITY_SEQUENCE_FOR_EACH_HPP_ +#define VCCC_UTILITY_SEQUENCE_FOR_EACH_HPP_ + +#include +#include +#include + +#include "vccc/__functional/identity.hpp" +#include "vccc/__functional/invoke.hpp" +#include "vccc/__type_traits/conjunction.hpp" +#include "vccc/__type_traits/is_invocable.hpp" + +namespace vccc { +namespace detail { + +template +struct sequence_for_each_invocable : std::false_type {}; + +template +struct sequence_for_each_invocable, F> + : conjunction< + is_invocable>... + > {}; + +} // namespace detail + +/// @addtogroup utility +/// @{ + +/// @brief performs f(std::integral_constant{}) for i in v... +template +constexpr std::enable_if_t, F>::value> +sequence_for_each(std::integer_sequence, F&& f) { + int dummy[] = { + (vccc::invoke(f, std::integral_constant{}), 0)... + }; + (void)dummy; +} + +/// @brief performs f(std::integral_constant{}) for i in [0, N) +template +constexpr std::enable_if_t, F>::value> +sequence_for_each(F&& f) { + return vccc::sequence_for_each(std::make_integer_sequence{}, std::forward(f)); +} + +/// @brief performs f(std::integral_constant{}) for i in [0, N) +template +constexpr std::enable_if_t, F>::value> +sequence_for_each(F&& f) { + return vccc::sequence_for_each(std::make_index_sequence{}, std::forward(f)); +} + +/// @} + +} // namespace vccc + +#endif // VCCC_UTILITY_SEQUENCE_FOR_EACH_HPP_ diff --git a/include/vccc/__variant/holds_alternative.hpp b/include/vccc/__variant/holds_alternative.hpp index 0032d2ea..b4450f68 100644 --- a/include/vccc/__variant/holds_alternative.hpp +++ b/include/vccc/__variant/holds_alternative.hpp @@ -23,6 +23,9 @@ struct variant_holds_alternative_visitor { } // namespace detail +/// @addtogroup variant +/// @{ + template::template count == 1) , int> = 0> @@ -30,6 +33,8 @@ constexpr bool holds_alternative(const variant& v) noexcept { return detail::variant_raw_visit(v.index(), v._base().union_, detail::variant_holds_alternative_visitor{}); } +/// @} + } // namespace vccc #endif // VCCC_VARIANTS_HOLDS_ALTERNATIVE_HPP diff --git a/include/vccc/algorithm.hpp b/include/vccc/algorithm.hpp index 9acaf636..e6236cd8 100644 --- a/include/vccc/algorithm.hpp +++ b/include/vccc/algorithm.hpp @@ -10,13 +10,19 @@ #include "vccc/__algorithm/shift.hpp" #include "vccc/__algorithm/ranges/all_of.hpp" #include "vccc/__algorithm/ranges/any_of.hpp" +#include "vccc/__algorithm/ranges/clamp.hpp" +#include "vccc/__algorithm/ranges/contains.hpp" +#include "vccc/__algorithm/ranges/contains_subrange.hpp" #include "vccc/__algorithm/ranges/copy.hpp" #include "vccc/__algorithm/ranges/count.hpp" #include "vccc/__algorithm/ranges/count_if.hpp" #include "vccc/__algorithm/ranges/equal.hpp" #include "vccc/__algorithm/ranges/find.hpp" +#include "vccc/__algorithm/ranges/find_end.hpp" +#include "vccc/__algorithm/ranges/find_first_of.hpp" #include "vccc/__algorithm/ranges/find_if.hpp" #include "vccc/__algorithm/ranges/find_if_not.hpp" +#include "vccc/__algorithm/ranges/find_last.hpp" #include "vccc/__algorithm/ranges/fold_left.hpp" #include "vccc/__algorithm/ranges/for_each.hpp" #include "vccc/__algorithm/ranges/for_each_n.hpp" @@ -28,6 +34,7 @@ #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/make_heap.hpp" #include "vccc/__algorithm/ranges/max.hpp" #include "vccc/__algorithm/ranges/max_element.hpp" #include "vccc/__algorithm/ranges/min.hpp" @@ -36,10 +43,13 @@ #include "vccc/__algorithm/ranges/mismatch.hpp" #include "vccc/__algorithm/ranges/none_of.hpp" #include "vccc/__algorithm/ranges/out_value_result.hpp" +#include "vccc/__algorithm/ranges/pop_heap.hpp" #include "vccc/__algorithm/ranges/search.hpp" #include "vccc/__algorithm/ranges/set_intersection.hpp" +#include "vccc/__algorithm/ranges/sort.hpp" +#include "vccc/__algorithm/ranges/sort_heap.hpp" #include "vccc/__algorithm/ranges/swap_ranges.hpp" -/// @defgroup algorithm +/// @defgroup algorithm algorithm #endif // VCCC_ALGORITHM_HPP diff --git a/include/vccc/array.hpp b/include/vccc/array.hpp new file mode 100644 index 00000000..9b2e6e4c --- /dev/null +++ b/include/vccc/array.hpp @@ -0,0 +1,12 @@ +// +// Created by YongGyu Lee on 4/11/24. +// + +#ifndef VCCC_ARRAY_HPP_ +#define VCCC_ARRAY_HPP_ + +#include "vccc/__array/to_array.hpp" + +/// @defgroup array array + +#endif // VCCC_ARRAY_HPP_ diff --git a/include/vccc/expected.hpp b/include/vccc/expected.hpp index 99b2dcda..748359c1 100644 --- a/include/vccc/expected.hpp +++ b/include/vccc/expected.hpp @@ -7,4 +7,6 @@ #include "vccc/__expected/expected.hpp" +/// @defgroup expected expected + #endif // VCCC_EXPECTED_HPP_ diff --git a/include/vccc/functional.hpp b/include/vccc/functional.hpp index 9332b676..6d281cda 100644 --- a/include/vccc/functional.hpp +++ b/include/vccc/functional.hpp @@ -5,6 +5,8 @@ # ifndef VCCC_FUNCTIONAL_FUNCTIONAL_HPP # define VCCC_FUNCTIONAL_FUNCTIONAL_HPP # +# include "vccc/__functional/bind_back.hpp" +# include "vccc/__functional/bind_front.hpp" # include "vccc/__functional/equal_to.hpp" # include "vccc/__functional/greater.hpp" # include "vccc/__functional/greater_equal.hpp" diff --git a/include/vccc/iterator.hpp b/include/vccc/iterator.hpp index 4bb302c1..03a4407f 100644 --- a/include/vccc/iterator.hpp +++ b/include/vccc/iterator.hpp @@ -6,7 +6,6 @@ #define VCCC_ITERATOR_HPP_ #include "vccc/__iterator/detail/iter_concept.hpp" -#include "vccc/__iterator/detail/iter_move_std.hpp" #include "vccc/__iterator/iterator_traits/forward_declare.hpp" #include "vccc/__iterator/iterator_traits/cxx20_iterator_traits.hpp" @@ -57,6 +56,7 @@ #include "vccc/__iterator/iter_value_t.hpp" #include "vccc/__iterator/iterator_tag.hpp" #include "vccc/__iterator/mergeable.hpp" +#include "vccc/__iterator/move_iterator.hpp" #include "vccc/__iterator/move_sentinel.hpp" #include "vccc/__iterator/next.hpp" #include "vccc/__iterator/output_iterator.hpp" @@ -64,6 +64,7 @@ #include "vccc/__iterator/prev.hpp" #include "vccc/__iterator/projected.hpp" #include "vccc/__iterator/random_access_iterator.hpp" +#include "vccc/__iterator/reverse_iterator.hpp" #include "vccc/__iterator/sentinel_for.hpp" #include "vccc/__iterator/sized_sentinel_for.hpp" #include "vccc/__iterator/sortable.hpp" diff --git a/include/vccc/memory.hpp b/include/vccc/memory.hpp index 76b6e9f9..541e3fbb 100644 --- a/include/vccc/memory.hpp +++ b/include/vccc/memory.hpp @@ -12,4 +12,6 @@ #include "vccc/__memory/pointer_traits.hpp" #include "vccc/__memory/to_address.hpp" +/// @defgroup memory memory + #endif // VCCC_MEMORY_HPP_ diff --git a/include/vccc/numeric.hpp b/include/vccc/numeric.hpp index d0604ef5..b99f8d82 100644 --- a/include/vccc/numeric.hpp +++ b/include/vccc/numeric.hpp @@ -8,9 +8,10 @@ # include "vccc/__numeric/average.hpp" # include "vccc/__numeric/float_equal.hpp" # include "vccc/__numeric/lossless_div.hpp" -# include "vccc/__numeric/sum.hpp" -# include "vccc/__numeric/stddev.hpp" # include "vccc/__numeric/norm.hpp" +# include "vccc/__numeric/saturate_cast.hpp" +# include "vccc/__numeric/stddev.hpp" +# include "vccc/__numeric/sum.hpp" /** @defgroup numeric numeric diff --git a/include/vccc/string_view.hpp b/include/vccc/string_view.hpp index e0831c2c..f28a04da 100644 --- a/include/vccc/string_view.hpp +++ b/include/vccc/string_view.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -866,7 +867,7 @@ struct hash { } }; -#if __cplusplus >= 202002L +#if __cplusplus >= 202002L && VCCC_HAS_TYPE_CHAR8_T_CXX20 template<> struct hash { std::size_t operator()(const vccc::u8string_view& sv) const noexcept { diff --git a/include/vccc/tuple.hpp b/include/vccc/tuple.hpp index 8a09ddb9..ec725905 100644 --- a/include/vccc/tuple.hpp +++ b/include/vccc/tuple.hpp @@ -8,6 +8,7 @@ # include "vccc/__tuple/apply.hpp" # include "vccc/__tuple/make_from_tuple.hpp" # include "vccc/__tuple/tuple_fold.hpp" +# include "vccc/__tuple/tuple_for_each.hpp" # include "vccc/__tuple/tuple_like.hpp" # include "vccc/__tuple/tuple_transform.hpp" diff --git a/include/vccc/type_traits.hpp b/include/vccc/type_traits.hpp index 355d05eb..de8cfddc 100644 --- a/include/vccc/type_traits.hpp +++ b/include/vccc/type_traits.hpp @@ -22,6 +22,7 @@ # include "vccc/__type_traits/common_type.hpp" # include "vccc/__type_traits/conjunction.hpp" # include "vccc/__type_traits/copy_cvref.hpp" +# include "vccc/__type_traits/copy_template.hpp" # include "vccc/__type_traits/disjunction.hpp" # include "vccc/__type_traits/empty.hpp" # include "vccc/__type_traits/has_operator_arrow.hpp" @@ -30,6 +31,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_character.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" diff --git a/include/vccc/utility.hpp b/include/vccc/utility.hpp index 6f46457b..a6003603 100644 --- a/include/vccc/utility.hpp +++ b/include/vccc/utility.hpp @@ -7,12 +7,15 @@ # # include "vccc/__utility/as_const.hpp" # include "vccc/__utility/assert.hpp" +# include "vccc/__utility/cmp.hpp" # include "vccc/__utility/compressed_pair.hpp" # include "vccc/__utility/cxx20_rel_ops.hpp" # include "vccc/__utility/in_place.hpp" +# include "vccc/__utility/in_range.hpp" # include "vccc/__utility/key_value.hpp" # include "vccc/__utility/nontype.hpp" # include "vccc/__utility/sequence.hpp" +# include "vccc/__utility/sequence_for_each.hpp" # include "vccc/__utility/time.hpp" # include "vccc/__utility/to_underlying.hpp" # include "vccc/__utility/type_sequence.hpp" diff --git a/test/algorithm_test.cpp b/test/algorithm_test.cpp index a256a7b6..ce863cbe 100644 --- a/test/algorithm_test.cpp +++ b/test/algorithm_test.cpp @@ -5,9 +5,15 @@ #include "test_core.hpp" #include +#include +#include +#include +#include +#include #include #include +#include "vccc/array.hpp" #include "vccc/algorithm.hpp" #include "vccc/string_view.hpp" #include "vccc/ranges.hpp" @@ -186,6 +192,198 @@ int Test() { TEST_ENSURES(ranges::equal(v_intersection, {5, 7, 7})); } + { + constexpr static auto v = {1, 2, 3, 1, 2, 3, 1, 2}; + + { + auto i1 = ranges::find_last(v.begin(), v.end(), 3); + auto i2 = ranges::find_last(v, 3); + TEST_ENSURES(ranges::distance(v.begin(), i1.begin()) == 5); + TEST_ENSURES(ranges::distance(v.begin(), i2.begin()) == 5); + } + { + auto i1 = ranges::find_last(v.begin(), v.end(), -3); + auto i2 = ranges::find_last(v, -3); + TEST_ENSURES(i1.begin() == v.end()); + TEST_ENSURES(i2.begin() == v.end()); + } + + auto abs = [](int x) { return x < 0 ? -x : x; }; + + { + auto pred = [](int x) { return x == 3; }; + auto i1 = ranges::find_last_if(v.begin(), v.end(), pred, abs); + auto i2 = ranges::find_last_if(v, pred, abs); + TEST_ENSURES(ranges::distance(v.begin(), i1.begin()) == 5); + TEST_ENSURES(ranges::distance(v.begin(), i2.begin()) == 5); + } + { + auto pred = [](int x) { return x == -3; }; + auto i1 = ranges::find_last_if(v.begin(), v.end(), pred, abs); + auto i2 = ranges::find_last_if(v, pred, abs); + TEST_ENSURES(i1.begin() == v.end()); + TEST_ENSURES(i2.begin() == v.end()); + } + + { + auto pred = [](int x) { return x == 1 or x == 2; }; + auto i1 = ranges::find_last_if_not(v.begin(), v.end(), pred, abs); + auto i2 = ranges::find_last_if_not(v, pred, abs); + TEST_ENSURES(ranges::distance(v.begin(), i1.begin()) == 5); + TEST_ENSURES(ranges::distance(v.begin(), i2.begin()) == 5); + } + { + auto pred = [](int x) { return x == 1 or x == 2 or x == 3; }; + auto i1 = ranges::find_last_if_not(v.begin(), v.end(), pred, abs); + auto i2 = ranges::find_last_if_not(v, pred, abs); + TEST_ENSURES(i1.begin() == v.end()); + TEST_ENSURES(i2.begin() == v.end()); + } + + using P = std::pair; + std::forward_list

list + { + {"one", 1}, {"two", 2}, {"three", 3}, + {"one", 4}, {"two", 5}, {"three", 6}, + }; + auto cmp_one = [](const vccc::string_view &s) { return s == "one"; }; + + // find latest element that satisfy the comparator, and projecting pair::first + const auto subrange = ranges::find_last_if(list, cmp_one, &P::first); + TEST_ENSURES(ranges::equal(subrange, std::vector

{{"one", 4}, {"two", 5}, {"three", 6}})); + } + + { // ranges::find_end + constexpr auto secret{"password password word..."_sv}; + constexpr auto wanted{"password"_sv}; + + auto s1 = ranges::find_end(secret.cbegin(), secret.cend(), wanted.cbegin(), wanted.cend()); + TEST_ENSURES(std::distance(secret.begin(), s1.begin()) == 9 && s1.size() == 8); + + auto s2 = ranges::find_end(secret, "word"_sv); + TEST_ENSURES(std::distance(secret.begin(), s2.begin()) == 18 && s2.size() == 4); + + auto s3 = ranges::find_end(secret, "ORD"_sv, [](const char x, const char y) { + return std::tolower(x) == std::tolower(y); + }); + TEST_ENSURES(std::distance(secret.begin(), s3.begin()) == 19 && s3.size() == 3); + + auto s4 = ranges::find_end(secret, "SWORD"_sv, {}, {}, [](char c) { return std::tolower(c); }); + TEST_ENSURES(std::distance(secret.begin(), s4.begin()) == 12 && s4.size() == 5); + } + + { // ranges::find_first_of + constexpr static auto haystack = {1, 2, 3, 4}; + constexpr static auto needles = {0, 3, 4, 3}; + + auto found1 = ranges::find_first_of(haystack.begin(), haystack.end(), + needles.begin(), needles.end()); + TEST_ENSURES(std::distance(haystack.begin(), found1) == 2); + + auto found2 = ranges::find_first_of(haystack, needles); + TEST_ENSURES(std::distance(haystack.begin(), found2) == 2); + + constexpr static auto negatives = {-6, -3, -4, -3}; + auto not_found = ranges::find_first_of(haystack, negatives); + TEST_ENSURES(not_found == haystack.end()); + + auto found3 = ranges::find_first_of(haystack, negatives, + [](int x, int y) { return x == -y; }); // uses a binary comparator + TEST_ENSURES(std::distance(haystack.begin(), found3) == 2); + + struct P { int x, y; }; + constexpr static auto p1 = {P{1, -1}, P{2, -2}, P{3, -3}, P{4, -4}}; + constexpr static auto p2 = {P{5, -5}, P{6, -3}, P{7, -5}, P{8, -3}}; + const auto found4 = ranges::find_first_of(p1, p2, {}, &P::y, &P::y); + TEST_ENSURES(std::distance(p1.begin(), found4) == 2); + } + + { // ranges::make_heap + std::vector h{1, 6, 1, 8, 0, 3, 3, 9, 8, 8, 7, 4, 9, 8, 9}; + + vccc::ranges::make_heap(h); + TEST_ENSURES(std::is_heap(h.begin(), h.end())); + + vccc::ranges::make_heap(h, std::greater<>{}); + TEST_ENSURES(std::is_heap(h.begin(), h.end()) == false); + TEST_ENSURES(std::is_heap(h.begin(), h.end(), std::greater<>{})); + } + + { // ranges::pop_heap + auto v = vccc::to_array({3, 1, 4, 1, 5, 9, 2, 6, 5, 3}); + + vccc::ranges::make_heap(v); + for (auto n {vccc::ssize(v)}; n >= 0; --n) { + vccc::ranges::pop_heap(v.begin(), v.begin() + n); + TEST_ENSURES(std::is_sorted(v.cbegin() + n, v.cend())); + } + + vccc::ranges::make_heap(v, vccc::ranges::greater{}); + for (auto n {vccc::ssize(v)}; n >= 0; --n) { + vccc::ranges::pop_heap(v.begin(), v.begin() + n, vccc::ranges::greater{}); + TEST_ENSURES(std::is_sorted(v.cbegin() + n, v.cend(), vccc::ranges::greater{})); + } + } + + { // ranges::sort_heap + auto v = vccc::to_array({3, 1, 4, 1, 5, 9}); + vccc::ranges::make_heap(v); + vccc::ranges::sort_heap(v); + TEST_ENSURES(std::is_sorted(v.begin(), v.end())); + + vccc::ranges::make_heap(v, vccc::ranges::greater{}); + vccc::ranges::sort_heap(v, vccc::ranges::greater{}); + TEST_ENSURES(std::is_sorted(v.begin(), v.end(), vccc::ranges::greater{})); + } + + { // ranges::sort + struct Particle { + std::string name; + double mass; // MeV + }; + + auto s = vccc::to_array({5, 7, 4, 2, 8, 6, 1, 9, 0, 3}); + namespace ranges = vccc::ranges; + + ranges::sort(s); + TEST_ENSURES(std::is_sorted(s.begin(), s.end())); + + ranges::sort(s, ranges::greater()); + TEST_ENSURES(std::is_sorted(s.begin(), s.end(), std::greater<>{})); + + Particle particles[] { + {"Electron", 0.511}, {"Muon", 105.66}, {"Tau", 1776.86}, + {"Positron", 0.511}, {"Proton", 938.27}, {"Neutron", 939.57} + }; + + // Sort by name using a projection + ranges::sort(particles, {}, &Particle::name); + TEST_ENSURES(ranges::equal(particles, {"Electron"_sv, "Muon"_sv, "Neutron"_sv, "Positron"_sv, "Proton"_sv, "Tau"_sv}, {}, &Particle::name)); + + // Sort by mass using a projection + ranges::sort(particles, {}, &Particle::mass); + TEST_ENSURES(ranges::equal(particles, {0.511, 0.511, 105.66, 938.27, 939.57, 1776.86}, {}, &Particle::mass)); + } + + { // ranges::contains, ranges::contains_subrange + constexpr auto haystack = vccc::to_array({3, 1, 4, 1, 5}); + constexpr auto needle = vccc::to_array({1, 4, 1}); + constexpr auto bodkin = vccc::to_array({2, 5, 2}); + auto increment = [](int x) { return ++x; }; + auto decrement = [](int x) { return --x; }; + + TEST_ENSURES(vccc::ranges::contains(haystack, 4)); + TEST_ENSURES(!vccc::ranges::contains(haystack, 6)); + TEST_ENSURES(vccc::ranges::contains(haystack, 6, increment)); + TEST_ENSURES(!vccc::ranges::contains(haystack, 1, increment)); + + TEST_ENSURES(vccc::ranges::contains_subrange(haystack, needle)); + TEST_ENSURES(!vccc::ranges::contains_subrange(haystack, bodkin)); + TEST_ENSURES(vccc::ranges::contains_subrange(haystack, bodkin, {}, increment)); + TEST_ENSURES(!vccc::ranges::contains_subrange(haystack, bodkin, {}, decrement)); + TEST_ENSURES(vccc::ranges::contains_subrange(haystack, bodkin, {}, {}, decrement)); + } + return TEST_RETURN_RESULT; } diff --git a/test/functional_test.cpp b/test/functional_test.cpp index 7175872d..ba1d5682 100644 --- a/test/functional_test.cpp +++ b/test/functional_test.cpp @@ -10,6 +10,15 @@ int foo(int a, int b, int c) { return (a + b) * c; } +constexpr int minus(int a, int b) { + return a - b; +} + +struct S { + int val; + constexpr int minus(int arg) const noexcept { return val - arg; } +}; + int main() { INIT_TEST("vccc::functional") @@ -38,6 +47,35 @@ int main() { return sum; }, 1, 2, 3) == 16); + { // bind_front + auto fifty_minus = vccc::bind_front(minus, 50); + TEST_ENSURES(fifty_minus(3) == 47); // equivalent to: minus(50, 3) == 47 + + auto member_minus = vccc::bind_front(&S::minus, S{50}); + TEST_ENSURES(member_minus(3) == 47); //: S tmp{50}; tmp.minus(3) == 47 + + static_assert(noexcept(S{}.minus(3)) == true, ""); + + // Noexcept-specification is preserved: + static_assert(!noexcept(fifty_minus(3)), ""); + static_assert(noexcept(member_minus(3)) == (__cplusplus > 201403L), ""); + + // Binding of a lambda: + auto plus = [](int a, int b) { return a + b; }; + auto forty_plus = vccc::bind_front(plus, 40); + TEST_ENSURES(forty_plus(7) == 47); // equivalent to: plus(40, 7) == 47 + + auto concat = [](auto&& a, auto&& b) { return std::forward(a) + std::forward(b); }; + auto hello = vccc::bind_front(concat, std::string("hello")); + TEST_ENSURES(std::move(hello)(", world") == "hello, world"); + TEST_ENSURES(hello(", world") == ", world"); + } + + { // bind_back + auto madd = [](int a, int b, int c) { return a * b + c; }; + auto mul_plus_seven = vccc::bind_back(madd, 7); + TEST_ENSURES(mul_plus_seven(4, 10) == 47); //: madd(4, 10, 7) == 47 + } return TEST_RETURN_RESULT; } diff --git a/test/iterator_test.cpp b/test/iterator_test.cpp index 6b5cf1bd..39ca732d 100644 --- a/test/iterator_test.cpp +++ b/test/iterator_test.cpp @@ -35,7 +35,7 @@ int main() { } { - int* p; + int* p = nullptr; static_assert(vccc::weakly_incrementable::value, ""); // operator==(vccc::unreachable_sentinel, p); @@ -154,5 +154,53 @@ int main() { } + { // common_iterator + { // iter_move + std::vector p{"Andromeda", "Cassiopeia", "Phoenix"}, q; + + using CTI = vccc::counted_iterator::iterator>; + using CI = vccc::common_iterator; + CI last{vccc::default_sentinel}; + + for (CI first{{p.begin(), 2}}; first != last; ++first) + q.emplace_back(/* ADL */ iter_move(first)); + TEST_ENSURES(p[0].empty() && q[0] == "Andromeda"); + TEST_ENSURES(p[1].empty() && q[1] == "Cassiopeia"); + TEST_ENSURES(!p[2].empty() && q.size() == 2); + } + { // iter_swap + using vector = std::vector; + + vector v1{"1", "2", "3", "4", "5"}, v2{"a", "b", "c", "d", "e"}; + + using CI = vccc::common_iterator< + vccc::counted_iterator::iterator>, + vccc::default_sentinel_t + >; + + CI first1{vccc::counted_iterator{v1.begin(), 3}}; + CI first2{vccc::counted_iterator{v2.begin(), 4}}; + CI last{vccc::default_sentinel}; + + for (; first1 != last && first2 != last; ++first1, ++first2) + iter_swap(first1, first2); // ADL + + TEST_ENSURES(vccc::ranges::equal(v1, vector{"a", "b", "c", "4", "5"})); + TEST_ENSURES(vccc::ranges::equal(v2, vector{"1", "2", "3", "d", "e"})); + } + } + + + { + std::vector v = {1, 2, 3}; + auto it = std::make_reverse_iterator(v.begin()); + + iter_move(it); + + + auto it2 = std::make_move_iterator(v.begin()); + bool res = it2 == vccc::move_sentinel{}; + } + return TEST_RETURN_RESULT; } diff --git a/test/log_test.cpp b/test/log_test.cpp index 3c7035e6..4bf6c917 100644 --- a/test/log_test.cpp +++ b/test/log_test.cpp @@ -117,10 +117,12 @@ int main() { bar b; TEST_ENSURES(vccc::Logger{}.to_string(b) == '@' + address_to_string(std::addressof(b))); - LOGD("THIS", "IS", "DEBUG"); - LOGI("THIS", "IS", "INFO"); - LOGW("THIS", "IS", "WARN"); - LOGE("THIS", "IS", "ERROR"); + LOGD("THIS ", "IS ", "DEBUG"); + LOGI("THIS ", "IS ", "INFO"); + LOGW("THIS ", "IS ", "WARN"); + LOGE("THIS ", "IS ", "ERROR"); + + vccc::Log(vccc::Logger::kError, "my tag ", "hello, ", 'w', 0, "rld", "!"); // test non-empty aggregate types diff --git a/test/ranges_test.cpp b/test/ranges_test.cpp index ffc13163..4fc14b27 100644 --- a/test/ranges_test.cpp +++ b/test/ranges_test.cpp @@ -19,6 +19,7 @@ #include #include "vccc/algorithm.hpp" +#include "vccc/array.hpp" #include "vccc/iterator.hpp" #include "vccc/ranges.hpp" #include "vccc/span.hpp" @@ -1120,5 +1121,71 @@ int main() { } } + { // ranges::zip_view, views::zip + auto print = [](auto const rem, auto const& range) { + std::cout << rem; + for (auto const& elem : range) + std::cout << elem << ' '; + std::cout << '\n'; + }; + + auto x = std::vector{1, 2, 3, 4}; + auto y = std::list{"a", "b", "c", "d", "e"}; + auto z = std::array{'A', 'B', 'C', 'D', 'E', 'F'}; + + print("x: ", x); + print("y: ", y); + print("z: ", z); + + for (std::tuple elem : vccc::views::zip(x, y, z) | vccc::views::common) { + std::cout << std::get<0>(elem) << ' ' + << std::get<1>(elem) << ' ' + << std::get<2>(elem) << '\n'; + + std::get(elem) += ('a' - 'A'); // modifies the element of z + } + + print("\nAfter modification, z: ", z); + TEST_ENSURES(vccc::ranges::equal(z, "abcdEF"_sv)); + + auto v1 = vccc::views::zip(x, y); + TEST_ENSURES(v1.size() == std::min(x.size(), y.size())); + TEST_ENSURES(v1.size() == 4); + + auto w = std::forward_list{1., 2.}; + [[maybe_unused]] auto v2 = vccc::views::zip(x, w); +// auto sz = v2.size(); +// auto sz = v2.size(); // Error, v2 does not have size(): + static_assert(!vccc::ranges::sized_range::value, ""); + } + + { // ranges::zip_transform_view, views::zip_transform + { + auto v1 = std::vector{1, 2, 3}; + auto v2 = std::list{1, 2, 3, 4}; + auto v3 = vccc::to_array({1, 2, 3, 4, 5}); + + auto add = [](auto a, auto b, auto c) { return a + b + c; }; + + auto sum = vccc::views::zip_transform(add, v1, v2, v3); + TEST_ENSURES(vccc::ranges::equal(sum, {3, 6, 9})); + } + + { + auto x = std::vector{1, 2, 3, 4, 5}; + auto y = std::deque{10, 20, 30}; + auto z = std::forward_list{100., 200.}; + + auto v1 = vccc::views::zip_transform(std::plus<>{}, x, y); + TEST_ENSURES(v1.size() == (std::min)(x.size(), y.size())); + TEST_ENSURES(v1.size() == 3); + TEST_ENSURES(vccc::ranges::equal(v1, {11, 22, 33})); + + [[maybe_unused]] auto v2 = vccc::views::zip_transform(std::plus<>{}, x, z); +// auto sz = v2.size(); // Error: z doesn't have size(), so neither does v2 + static_assert(not vccc::ranges::sized_range::value, ""); + } + } + return TEST_RETURN_RESULT; } diff --git a/test/type_traits_test.cpp b/test/type_traits_test.cpp index d2431d05..03e59ac5 100644 --- a/test/type_traits_test.cpp +++ b/test/type_traits_test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -140,5 +141,10 @@ int main() { #endif } + { // copy_template + static_assert(std::is_same, std::tuple>, std::tuple>::value, ""); + static_assert(std::is_same, std::tuple, std::vector>, std::tuple, std::vector>>::value, ""); + } + return TEST_RETURN_RESULT; }