From libcxx-commits at lists.llvm.org Sat Feb 1 04:51:11 2025 From: libcxx-commits at lists.llvm.org (=?UTF-8?B?0JTQvNC40YLRgNC40Lkg0JjQt9Cy0L7Qu9C+0LI=?= via libcxx-commits) Date: Sat, 01 Feb 2025 04:51:11 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Support `constexpr` for `std::stable_sort` in radix sort branch (PR #125284) In-Reply-To: Message-ID: <679e18bf.170a0220.318ba1.dddb@mx.google.com> https://github.com/izvolov updated https://github.com/llvm/llvm-project/pull/125284 >From 96d373c9a4d88d5da1581f1d3a00e85dbdc76744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=98=D0=B7?= =?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BE=D0=B2?= Date: Fri, 31 Jan 2025 22:00:09 +0300 Subject: [PATCH 1/3] constexpr --- libcxx/include/__algorithm/radix_sort.h | 24 +++++++++---------- libcxx/include/__algorithm/stable_sort.h | 6 +++++ .../alg.sort/stable.sort/stable_sort.pass.cpp | 3 ++- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/libcxx/include/__algorithm/radix_sort.h b/libcxx/include/__algorithm/radix_sort.h index de6927995e74c89..89df4e19fd00fb5 100644 --- a/libcxx/include/__algorithm/radix_sort.h +++ b/libcxx/include/__algorithm/radix_sort.h @@ -67,7 +67,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 14 template -_LIBCPP_HIDE_FROM_ABI pair<_OutputIterator, __iter_value_type<_InputIterator>> +_LIBCPP_HIDE_FROM_ABI constexpr pair<_OutputIterator, __iter_value_type<_InputIterator>> __partial_sum_max(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { if (__first == __last) return {__result, 0}; @@ -109,7 +109,7 @@ struct __counting_sort_traits { }; template -_LIBCPP_HIDE_FROM_ABI auto __nth_radix(size_t __radix_number, _Radix __radix, _Integer __n) { +_LIBCPP_HIDE_FROM_ABI constexpr auto __nth_radix(size_t __radix_number, _Radix __radix, _Integer __n) { static_assert(is_unsigned<_Integer>::value); using __traits = __counting_sort_traits<_Integer, _Radix>; @@ -117,7 +117,7 @@ _LIBCPP_HIDE_FROM_ABI auto __nth_radix(size_t __radix_number, _Radix __radix, _I } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __collect(_ForwardIterator __first, _ForwardIterator __last, _Map __map, _RandomAccessIterator __counters) { using __value_type = __iter_value_type<_ForwardIterator>; using __traits = __counting_sort_traits<__value_type, _Map>; @@ -129,7 +129,7 @@ __collect(_ForwardIterator __first, _ForwardIterator __last, _Map __map, _Random } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __dispose(_ForwardIterator __first, _ForwardIterator __last, _RandomAccessIterator1 __result, @@ -147,7 +147,7 @@ template -_LIBCPP_HIDE_FROM_ABI bool __collect_impl( +_LIBCPP_HIDE_FROM_ABI constexpr bool __collect_impl( _ForwardIterator __first, _ForwardIterator __last, _Map __map, @@ -177,7 +177,7 @@ _LIBCPP_HIDE_FROM_ABI bool __collect_impl( } template -_LIBCPP_HIDE_FROM_ABI bool +_LIBCPP_HIDE_FROM_ABI constexpr bool __collect(_ForwardIterator __first, _ForwardIterator __last, _Map __map, @@ -191,7 +191,7 @@ __collect(_ForwardIterator __first, } template -_LIBCPP_HIDE_FROM_ABI void __dispose_backward( +_LIBCPP_HIDE_FROM_ABI constexpr void __dispose_backward( _BidirectionalIterator __first, _BidirectionalIterator __last, _RandomAccessIterator1 __result, @@ -206,7 +206,7 @@ _LIBCPP_HIDE_FROM_ABI void __dispose_backward( } template -_LIBCPP_HIDE_FROM_ABI _RandomAccessIterator +_LIBCPP_HIDE_FROM_ABI constexpr _RandomAccessIterator __counting_sort_impl(_ForwardIterator __first, _ForwardIterator __last, _RandomAccessIterator __result, _Map __map) { using __value_type = __iter_value_type<_ForwardIterator>; using __traits = __counting_sort_traits<__value_type, _Map>; @@ -225,7 +225,7 @@ template , _Map, _Radix>::__radix_count == 1, int> = 0> -_LIBCPP_HIDE_FROM_ABI void __radix_sort_impl( +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort_impl( _RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer, @@ -245,7 +245,7 @@ template < class _Radix, enable_if_t< __radix_sort_traits<__iter_value_type<_RandomAccessIterator1>, _Map, _Radix>::__radix_count % 2 == 0, int> = 0 > -_LIBCPP_HIDE_FROM_ABI void __radix_sort_impl( +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort_impl( _RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer_begin, @@ -307,7 +307,7 @@ struct __low_byte_fn { }; template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer, @@ -318,7 +318,7 @@ __radix_sort(_RandomAccessIterator1 __first, } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer) { std::__radix_sort(__first, __last, __buffer, __identity{}, __low_byte_fn{}); } diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 3cfbcf08d2c5c44..21bc3a947069c0d 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -253,6 +253,12 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort( if constexpr (__allowed_radix_sort) { if (__len <= __buff_size && __len >= static_cast(__radix_sort_min_bound()) && __len <= static_cast(__radix_sort_max_bound())) { + for (auto* p = __buff; p < __buff + __buff_size; ++p) { + std::__construct_at(p, 0); + } + __destruct_n __d(__buff_size); + unique_ptr __h2(__buff, __d); + std::__radix_sort(__first, __last, __buff); return; } diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index b3b458808c44ad5..1e529529b78f96f 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -178,8 +178,9 @@ TEST_CONSTEXPR_CXX26 bool test() { test_larger_sorts(1009); test_larger_sorts(1024); test_larger_sorts(1031); - test_larger_sorts(2053); } + // test constexprness of radix sort branch + test_larger_sorts(2053); // check that the algorithm works without memory #ifndef TEST_HAS_NO_EXCEPTIONS >From 4d5783d1ead702b4b1383e8aa873456303beaf6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=98=D0=B7?= =?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BE=D0=B2?= Date: Sat, 1 Feb 2025 09:09:19 +0300 Subject: [PATCH 2/3] fix-case --- libcxx/include/__algorithm/stable_sort.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 21bc3a947069c0d..8659039dcf24b79 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -253,8 +253,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort( if constexpr (__allowed_radix_sort) { if (__len <= __buff_size && __len >= static_cast(__radix_sort_min_bound()) && __len <= static_cast(__radix_sort_max_bound())) { - for (auto* p = __buff; p < __buff + __buff_size; ++p) { - std::__construct_at(p, 0); + for (auto* __p = __buff; __p < __buff + __buff_size; ++__p) { + std::__construct_at(__p, 0); } __destruct_n __d(__buff_size); unique_ptr __h2(__buff, __d); >From 85e5de009cf69f4166cff46433b97ad4f530779a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=98=D0=B7?= =?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BE=D0=B2?= Date: Sat, 1 Feb 2025 15:50:03 +0300 Subject: [PATCH 3/3] smaller --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 1e529529b78f96f..8c82e7d8eea00ff 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -176,11 +176,11 @@ TEST_CONSTEXPR_CXX26 bool test() { test_larger_sorts(997); test_larger_sorts(1000); test_larger_sorts(1009); - test_larger_sorts(1024); test_larger_sorts(1031); + test_larger_sorts(2053); } // test constexprness of radix sort branch - test_larger_sorts(2053); + test_larger_sorts(1024); // check that the algorithm works without memory #ifndef TEST_HAS_NO_EXCEPTIONS From libcxx-commits at lists.llvm.org Sat Feb 1 08:25:43 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sat, 01 Feb 2025 08:25:43 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add a benchmark for std::reverse (PR #125262) In-Reply-To: Message-ID: <679e4b07.170a0220.390af0.3b5c@mx.google.com> https://github.com/philnik777 approved this pull request. https://github.com/llvm/llvm-project/pull/125262 From libcxx-commits at lists.llvm.org Sun Feb 2 03:08:15 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Sun, 02 Feb 2025 03:08:15 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <679f521e.170a0220.498ec.18a5@mx.google.com> https://github.com/mordante edited https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Sun Feb 2 03:08:15 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Sun, 02 Feb 2025 03:08:15 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <679f521f.050a0220.2c58d8.552e@mx.google.com> https://github.com/mordante requested changes to this pull request. Sorry I seem to have missed this patch before, Thanks for working on this! I have a hard time to review the patch - the patch does not describe what it does, there are only benchmarks - the code has no comment. Did you benchmark what to overhead for the types are? https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Sun Feb 2 03:08:15 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Sun, 02 Feb 2025 03:08:15 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <679f521f.050a0220.320d4.4202@mx.google.com> ================ @@ -447,10 +449,41 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) { } # endif +template ---------------- mordante wrote: Please add some documentation what this function does. The code is not easy to understand and I don't think it does what I expect it to do. Does the code optimize `std::format("{}", 42)`? https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Sun Feb 2 03:08:16 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Sun, 02 Feb 2025 03:08:16 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <679f5220.170a0220.70f06.15f0@mx.google.com> ================ @@ -447,10 +449,41 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) { } # endif +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional> __try_constant_folding_format( + basic_string_view<_CharT> __fmt, + basic_format_args>, _CharT>> __args) { + // [[gnu::pure]] is added to ensure that the compiler always knows that this call can be eliminated. + if (bool __is_identity = + [&] [[__gnu__::__pure__]] { return std::ranges::find_first_of(__fmt, array{'{', '}'}) == __fmt.end(); }(); ---------------- mordante wrote: Why testing against `'{'` instead of `_Chart('{')`? https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Sun Feb 2 04:27:43 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Sun, 02 Feb 2025 04:27:43 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][TZDB] Fixes %z escaping. (PR #125399) Message-ID: https://github.com/mordante created https://github.com/llvm/llvm-project/pull/125399 The previous tested TZDB did not contain %z for the rule letters. The usage of %z in TZDB 2024b revealed a bug in the implementation. The patch fixes it and has been locally tested with TZDB 2024b. Fixes: https://github.com/llvm/llvm-project/issues/108957 >From ee1a6d842a0cc46fd1792199ee1ca4fc15556113 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sun, 2 Feb 2025 13:23:14 +0100 Subject: [PATCH] [libc++][TZDB] Fixes %z escaping. The previous tested TZDB did not contain %z for the rule letters. The usage of %z in TZDB 2024b revealed a bug in the implementation. The patch fixes it and has been locally tested with TZDB 2024b. Fixes: https://github.com/llvm/llvm-project/issues/108957 --- libcxx/src/experimental/time_zone.cpp | 2 +- .../time.zone.members/get_info.sys_time.pass.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libcxx/src/experimental/time_zone.cpp b/libcxx/src/experimental/time_zone.cpp index 764a89ab513c86..b11e52fec65c4f 100644 --- a/libcxx/src/experimental/time_zone.cpp +++ b/libcxx/src/experimental/time_zone.cpp @@ -668,7 +668,7 @@ __first_rule(seconds __stdoff, const vector<__tz::__rule>& __rules) { __continuation_end, __continuation.__stdoff + __save, chrono::duration_cast(__save), - __continuation.__format}, + chrono::__format(__continuation, __continuation.__format, __save)}, true}; } diff --git a/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp b/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp index 7f08c64d5e0e71..afd1273421f398 100644 --- a/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp +++ b/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp @@ -157,7 +157,6 @@ static void test_abbrev(std::string_view input, std::string_view expected) { TEST_LIBCPP_REQUIRE(result == expected, TEST_WRITE_CONCATENATED("\nExpected ", expected, "\nActual ", result, '\n')); } -// This format is valid, however is not used in the tzdata.zi. static void percentage_z_format() { test_abbrev( R"( @@ -188,6 +187,12 @@ Z Format 0:45 F %z)", R F 1999 max - Jan 5 0 -1 foo Z Format 0:45 F %z)", "-0015"); + + test_abbrev( + R"( +Z Format -1:2:20 - LMT 1912 Ja 1 1u +-1 - %z)", + "-01"); } int main(int, const char**) { From libcxx-commits at lists.llvm.org Sun Feb 2 04:28:16 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Sun, 02 Feb 2025 04:28:16 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][TZDB] Fixes %z escaping. (PR #125399) In-Reply-To: Message-ID: <679f64e0.630a0220.3aada3.2af1@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-libcxx Author: Mark de Wever (mordante)
Changes The previous tested TZDB did not contain %z for the rule letters. The usage of %z in TZDB 2024b revealed a bug in the implementation. The patch fixes it and has been locally tested with TZDB 2024b. Fixes: https://github.com/llvm/llvm-project/issues/108957 --- Full diff: https://github.com/llvm/llvm-project/pull/125399.diff 2 Files Affected: - (modified) libcxx/src/experimental/time_zone.cpp (+1-1) - (modified) libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp (+6-1) ``````````diff diff --git a/libcxx/src/experimental/time_zone.cpp b/libcxx/src/experimental/time_zone.cpp index 764a89ab513c86..b11e52fec65c4f 100644 --- a/libcxx/src/experimental/time_zone.cpp +++ b/libcxx/src/experimental/time_zone.cpp @@ -668,7 +668,7 @@ __first_rule(seconds __stdoff, const vector<__tz::__rule>& __rules) { __continuation_end, __continuation.__stdoff + __save, chrono::duration_cast(__save), - __continuation.__format}, + chrono::__format(__continuation, __continuation.__format, __save)}, true}; } diff --git a/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp b/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp index 7f08c64d5e0e71..afd1273421f398 100644 --- a/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp +++ b/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp @@ -157,7 +157,6 @@ static void test_abbrev(std::string_view input, std::string_view expected) { TEST_LIBCPP_REQUIRE(result == expected, TEST_WRITE_CONCATENATED("\nExpected ", expected, "\nActual ", result, '\n')); } -// This format is valid, however is not used in the tzdata.zi. static void percentage_z_format() { test_abbrev( R"( @@ -188,6 +187,12 @@ Z Format 0:45 F %z)", R F 1999 max - Jan 5 0 -1 foo Z Format 0:45 F %z)", "-0015"); + + test_abbrev( + R"( +Z Format -1:2:20 - LMT 1912 Ja 1 1u +-1 - %z)", + "-01"); } int main(int, const char**) { ``````````
https://github.com/llvm/llvm-project/pull/125399 From libcxx-commits at lists.llvm.org Sun Feb 2 05:21:39 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Sun, 02 Feb 2025 05:21:39 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] implement std::flat_set (PR #125241) In-Reply-To: Message-ID: <679f7163.a70a0220.18971e.502e@mx.google.com> https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/125241 >From a0f80fcd8c55154c89535488479872de34e5c8dd Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Fri, 31 Jan 2025 15:53:09 +0000 Subject: [PATCH 1/2] [libc++] implement std::flat_set --- libcxx/include/CMakeLists.txt | 2 + libcxx/include/__flat_set/flat_set.h | 853 ++++++++++++++++++ libcxx/include/flat_set | 59 ++ libcxx/include/module.modulemap | 11 + .../flat.set/flat.set.capacity/empty.pass.cpp | 48 + .../flat.set.capacity/empty.verify.cpp | 20 + .../flat.set.capacity/max_size.pass.cpp | 63 ++ .../flat.set/flat.set.capacity/size.pass.cpp | 66 ++ .../flat.set/flat.set.cons/alloc.pass.cpp | 60 ++ .../assign_initializer_list.pass.cpp | 56 ++ .../flat.set/flat.set.cons/compare.pass.cpp | 83 ++ .../flat.set.cons/containers.pass.cpp | 158 ++++ .../flat.set/flat.set.cons/copy.pass.cpp | 64 ++ .../flat.set.cons/copy_alloc.pass.cpp | 63 ++ .../copy_assign.addressof.compile.pass.cpp | 30 + .../flat.set.cons/copy_assign.pass.cpp | 85 ++ .../flat.set.cons/deduct.compile.pass.cpp | 49 + .../flat.set/flat.set.cons/deduct.pass.cpp | 341 +++++++ .../flat.set.cons/deduct_pmr.pass.cpp | 94 ++ .../flat.set/flat.set.cons/default.pass.cpp | 65 ++ .../flat.set.cons/default_noexcept.pass.cpp | 58 ++ .../flat.set.cons/dtor_noexcept.pass.cpp | 57 ++ .../flat.set.cons/initializer_list.pass.cpp | 151 ++++ .../flat.set/flat.set.cons/iter_iter.pass.cpp | 136 +++ .../flat.set/flat.set.cons/move.pass.cpp | 83 ++ .../flat.set.cons/move_alloc.pass.cpp | 75 ++ .../flat.set.cons/move_assign.pass.cpp | 69 ++ .../flat.set.cons/move_assign_clears.pass.cpp | 101 +++ .../move_assign_noexcept.pass.cpp | 85 ++ .../flat.set.cons/move_exceptions.pass.cpp | 58 ++ .../flat.set.cons/move_noexcept.pass.cpp | 94 ++ .../flat.set/flat.set.cons/pmr.pass.cpp | 322 +++++++ .../flat.set/flat.set.cons/range.pass.cpp | 173 ++++ .../flat.set.cons/sorted_container.pass.cpp | 143 +++ .../sorted_initializer_list.pass.cpp | 150 +++ .../flat.set.cons/sorted_iter_iter.pass.cpp | 156 ++++ .../flat.set.erasure/erase_if.pass.cpp | 89 ++ .../erase_if_exceptions.pass.cpp | 128 +++ .../flat.set.iterators/iterator.pass.cpp | 93 ++ .../iterator_comparison.pass.cpp | 154 ++++ ...rator_concept_conformance.compile.pass.cpp | 77 ++ ...range_concept_conformance.compile.pass.cpp | 52 ++ .../reverse_iterator.pass.cpp | 87 ++ .../flat.set.modifiers/clear.pass.cpp | 62 ++ .../flat.set.modifiers/emplace.pass.cpp | 141 +++ .../flat.set.modifiers/emplace_hint.pass.cpp | 154 ++++ .../flat.set.modifiers/erase_iter.pass.cpp | 121 +++ .../erase_iter_iter.pass.cpp | 91 ++ .../flat.set.modifiers/erase_key.pass.cpp | 91 ++ .../erase_key_transparent.pass.cpp | 142 +++ .../flat.set.modifiers/extract.pass.cpp | 83 ++ .../flat.set.modifiers/insert_cv.pass.cpp | 78 ++ .../insert_initializer_list.pass.cpp | 67 ++ .../insert_iter_cv.pass.cpp | 74 ++ .../insert_iter_iter.pass.cpp | 87 ++ .../insert_iter_rv.pass.cpp | 73 ++ .../flat.set.modifiers/insert_range.pass.cpp | 105 +++ .../flat.set.modifiers/insert_rv.pass.cpp | 80 ++ .../insert_sorted_initializer_list.pass.cpp | 58 ++ .../insert_sorted_iter_iter.pass.cpp | 77 ++ .../insert_transparent.pass.cpp | 169 ++++ .../flat.set.modifiers/replace.pass.cpp | 72 ++ .../swap_exception.pass.cpp | 61 ++ .../flat.set.modifiers/swap_free.pass.cpp | 94 ++ .../flat.set.modifiers/swap_member.pass.cpp | 92 ++ .../flat.set/flat.set.observers/comp.pass.cpp | 72 ++ .../flat.set.operations/contains.pass.cpp | 69 ++ .../contains_transparent.pass.cpp | 70 ++ .../flat.set.operations/count.pass.cpp | 69 ++ .../count_transparent.pass.cpp | 71 ++ .../flat.set.operations/equal_range.pass.cpp | 77 ++ .../equal_range_transparent.pass.cpp | 97 ++ .../flat.set.operations/find.pass.cpp | 53 ++ .../find_transparent.pass.cpp | 88 ++ .../flat.set.operations/lower_bound.pass.cpp | 70 ++ .../lower_bound_transparent.pass.cpp | 94 ++ .../flat.set.operations/upper_bound.pass.cpp | 71 ++ .../upper_bound_transparent.pass.cpp | 93 ++ .../container.adaptors/flat.set/helpers.h | 294 ++++++ .../flat.set/incomplete_type.pass.cpp | 33 + .../flat.set/op_compare.pass.cpp | 105 +++ .../flat.set/types.compile.pass.cpp | 94 ++ 82 files changed, 8453 insertions(+) create mode 100644 libcxx/include/__flat_set/flat_set.h create mode 100644 libcxx/include/flat_set create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/helpers.h create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8dac823503d73f5..75acf9f7899ff66 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -367,6 +367,7 @@ set(files __flat_map/sorted_equivalent.h __flat_map/sorted_unique.h __flat_map/utils.h + __flat_set/flat_set.h __format/buffer.h __format/concepts.h __format/container_adaptor.h @@ -986,6 +987,7 @@ set(files fenv.h filesystem flat_map + flat_set float.h format forward_list diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h new file mode 100644 index 000000000000000..c920632c453bf5e --- /dev/null +++ b/libcxx/include/__flat_set/flat_set.h @@ -0,0 +1,853 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FLAT_set_FLAT_SET_H +#define _LIBCPP___FLAT_set_FLAT_SET_H + +#include <__algorithm/lexicographical_compare_three_way.h> +#include <__algorithm/min.h> +#include <__algorithm/ranges_adjacent_find.h> +#include <__algorithm/ranges_equal.h> +#include <__algorithm/ranges_inplace_merge.h> +#include <__algorithm/ranges_lower_bound.h> +#include <__algorithm/ranges_partition_point.h> +#include <__algorithm/ranges_sort.h> +#include <__algorithm/ranges_unique.h> +#include <__algorithm/ranges_upper_bound.h> +#include <__algorithm/remove_if.h> +#include <__assert> +#include <__compare/synth_three_way.h> +#include <__concepts/swappable.h> +#include <__config> +#include <__cstddef/byte.h> +#include <__cstddef/ptrdiff_t.h> +#include <__flat_map/sorted_unique.h> +#include <__functional/invoke.h> +#include <__functional/is_transparent.h> +#include <__functional/operations.h> +#include <__fwd/vector.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/ranges_iterator_traits.h> +#include <__iterator/reverse_iterator.h> +#include <__memory/allocator_traits.h> +#include <__memory/uses_allocator.h> +#include <__memory/uses_allocator_construction.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/container_compatible_range.h> +#include <__ranges/drop_view.h> +#include <__ranges/from_range.h> +#include <__ranges/ref_view.h> +#include <__ranges/size.h> +#include <__ranges/subrange.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/container_traits.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_allocator.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_same.h> +#include <__utility/exception_guard.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include <__utility/scope_guard.h> +#include <__vector/vector.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template , class _KeyContainer = vector<_Key>> +class flat_set { + template + friend class flat_set; + + static_assert(is_same_v<_Key, typename _KeyContainer::value_type>); + static_assert(!is_same_v<_KeyContainer, std::vector>, "vector is not a sequence container"); + +public: + // types + using key_type = _Key; + using value_type = _Key; + using key_compare = __type_identity_t<_Compare>; + using value_compare = _Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename _KeyContainer::size_type; + using difference_type = typename _KeyContainer::difference_type; + using iterator = typename _KeyContainer::const_iterator; + using const_iterator = iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using container_type = _KeyContainer; + +private: + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = + uses_allocator::value; + + _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; + +public: + // [flat.set.cons], construct/copy/destroy + _LIBCPP_HIDE_FROM_ABI + flat_set() noexcept(is_nothrow_default_constructible_v<_KeyContainer> && is_nothrow_default_constructible_v<_Compare>) + : __keys_(), __compare_() {} + + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other) noexcept( + is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : __keys_(std::move(__other.__keys_)), __compare_(std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + // gcc does not like the `throw` keyword in a conditionally noexcept function + if constexpr (!(is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>)) { + throw; + } +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const key_compare& __comp) : __keys_(), __compare_(__comp) {} + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + __sort_and_unique(); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(), __compare_(__comp) { + insert(__first, __last); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(__first, __last), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg) + : flat_set(from_range, std::forward<_Range>(__rg), key_compare()) {} + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp) : flat_set(__comp) { + insert_range(std::forward<_Range>(__rg)); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(__il.begin(), __il.end(), __comp) {} + + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : flat_set(__ctor_uses_allocator_tag{}, __alloc, std::move(__other.__keys_), std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + throw; +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(sorted_unique, __first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, + _InputIterator __first, + _InputIterator __last, + const key_compare& __comp, + const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(sorted_unique, __first, __last); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert_range(std::forward<_Range>(__rg)); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert_range(std::forward<_Range>(__rg)); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(initializer_list __il) { + clear(); + insert(__il); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(flat_set&& __other) noexcept( + is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_Compare>) { + // No matter what happens, we always want to clear the other container before returning + // since we moved from it + auto __clear_other_guard = std::__make_scope_guard([&]() noexcept { __other.clear() /* noexcept */; }); + { + // If an exception is thrown, we have no choice but to clear *this to preserve invariants + auto __on_exception = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__other.__keys_); + __compare_ = std::move(__other.__compare_); + __on_exception.__complete(); + } + return *this; + } + + // iterators + _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + + _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return begin(); } + _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return end(); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + // [flat.set.capacity], capacity + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __keys_.empty(); } + + _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __keys_.size(); } + + _LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept { return __keys_.max_size(); } + + // [flat.set.modifiers], modifiers + template + _LIBCPP_HIDE_FROM_ABI pair emplace(_Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __try_emplace(std::forward<_Args>(__args)...); + } else { + return __try_emplace(_Key(std::forward<_Args>(__args)...)); + } + } + + template + _LIBCPP_HIDE_FROM_ABI iterator emplace_hint(const_iterator __hint, _Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __emplace_hint(std::move(__hint), std::forward<_Args>(__args)...); + } else { + return __emplace_hint(std::move(__hint), _Key(std::forward<_Args>(__args)...)); + } + } + + _LIBCPP_HIDE_FROM_ABI pair insert(const value_type& __x) { return emplace(__x); } + + _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { + return emplace(std::forward<_Kp>(__x)); + } + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, const value_type& __x) { + return emplace_hint(__hint, __x); + } + + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, value_type&& __x) { + return emplace_hint(__hint, std::move(__x)); + } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { + return emplace_hint(__hint, std::forward<_Kp>(__x)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, _InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { + if constexpr (ranges::sized_range<_Range>) { + __reserve(ranges::size(__range)); + } + + __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + } + + _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } + + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, initializer_list __il) { + insert(sorted_unique, __il.begin(), __il.end()); + } + + _LIBCPP_HIDE_FROM_ABI container_type extract() && { + auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; }); + auto __ret = std::move(__keys_); + return __ret; + } + + _LIBCPP_HIDE_FROM_ABI void replace(container_type&& __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys), "Either the key container is not sorted or it contains duplicates"); + auto __guard = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__keys); + __guard.__complete(); + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __position) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_iter = __keys_.erase(__position); + __on_failure.__complete(); + return __key_iter; + } + + // The following overload is the same as the iterator overload + // iterator erase(const_iterator __position); + + _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __x) { + auto __iter = find(__x); + if (__iter != end()) { + erase(__iter); + return 1; + } + return 0; + } + + template + requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + !is_convertible_v<_Kp &&, const_iterator>) + _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { + auto [__first, __last] = equal_range(__x); + auto __res = __last - __first; + erase(__first, __last); + return __res; + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_it = __keys_.erase(__first, __last); + __on_failure.__complete(); + return __key_it; + } + + _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __y) noexcept { + // warning: The spec has unconditional noexcept, which means that + // if any of the following functions throw an exception, + // std::terminate will be called. + // This is discussed in P2767, which hasn't been voted on yet. + ranges::swap(__compare_, __y.__compare_); + ranges::swap(__keys_, __y.__keys_); + } + + _LIBCPP_HIDE_FROM_ABI void clear() noexcept { __keys_.clear(); } + + // observers + _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __compare_; } + _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __compare_; } + + // set operations + _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __x) { return __find_impl(*this, __x); } + + _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { + return __find_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { + return __find_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { + return contains(__x) ? 1 : 0; + } + + _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { + return find(__x) != end(); + } + + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) { + return __equal_range_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) const { + return __equal_range_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { + return __equal_range_impl(*this, __x); + } + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { + return __equal_range_impl(*this, __x); + } + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const flat_set& __x, const flat_set& __y) { + return ranges::equal(__x, __y); + } + + friend _LIBCPP_HIDE_FROM_ABI auto operator<=>(const flat_set& __x, const flat_set& __y) { + return std::lexicographical_compare_three_way( + __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); + } + + friend _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __x, flat_set& __y) noexcept { __x.swap(__y); } + +private: + struct __ctor_uses_allocator_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_tag() = default; + }; + struct __ctor_uses_allocator_empty_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_empty_tag() = default; + }; + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), + __compare_(std::forward<_CompArg>(__comp)...) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc)), + __compare_(std::forward<_CompArg>(__comp)...) {} + + _LIBCPP_HIDE_FROM_ABI bool __is_sorted_and_unique(auto&& __key_container) const { + auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) { return !__compare_(__x, __y); }; + return ranges::adjacent_find(__key_container, __greater_or_equal_to) == ranges::end(__key_container); + } + + // This function is only used in constructors. So there is not exception handling in this function. + // If the function exits via an exception, there will be no flat_set object constructed, thus, there + // is no invariant state to preserve + _LIBCPP_HIDE_FROM_ABI void __sort_and_unique() { + ranges::sort(__keys_, __compare_); + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } else { + for (; __first != __last; ++__first) { + __keys_.insert(__keys_.end(), *__first); + } + } + if (size() != __old_size) { + if constexpr (!_WasSorted) { + ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); + } else { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__is_sorted_and_unique(__keys_ | ranges::views::drop(__old_size)), + "Either the key container is not sorted or it contains duplicates"); + } + ranges::inplace_merge(__keys_.begin(), __keys_.begin() + __old_size, __keys_.end(), __compare_); + + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + __on_failure.__complete(); + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __find_impl(_Self&& __self, const _Kp& __key) { + auto __it = __self.lower_bound(__key); + auto __last = __self.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return __last; + } + return __it; + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __equal_range_impl(_Self&& __self, const _Kp& __key) { + auto __it = ranges::lower_bound(__self.__keys_, __key, __self.__compare_); + auto __last = __self.__keys_.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return std::make_pair(__it, __it); + } + return std::make_pair(__it, std::next(__it)); + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_exact_pos(const_iterator __it, _KeyArg&& __key) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { + if constexpr (!__container_traits<_KeyContainer>::__emplacement_has_strong_exception_safety_guarantee) { + clear() /* noexcept */; + } + }); + auto __key_it = __keys_.emplace(__it, std::forward<_KeyArg>(__key)); + __on_failure.__complete(); + return __key_it; + } + + template + _LIBCPP_HIDE_FROM_ABI pair __try_emplace(_Kp&& __key) { + auto __it = lower_bound(__key); + if (__it == end() || __compare_(__key, *__it)) { + return pair(__emplace_exact_pos(__it, std::forward<_Kp>(__key)), true); + } else { + return pair(std::move(__it), false); + } + } + + template + _LIBCPP_HIDE_FROM_ABI bool __is_hint_correct(const_iterator __hint, _Kp&& __key) { + if (__hint != cbegin() && !__compare_(*(__hint - 1), __key)) { + return false; + } + if (__hint != cend() && __compare_(*__hint, __key)) { + return false; + } + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint(const_iterator __hint, _Kp&& __key) { + if (__is_hint_correct(__hint, __key)) { + if (__hint == cend() || __compare_(__key, *__hint)) { + return __emplace_exact_pos(__hint, std::forward<_Kp>(__key)); + } else { + // key equals + return __hint; + } + } else { + return __try_emplace(std::forward<_Kp>(__key)).first; + } + } + + _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __size) { + if constexpr (requires { __keys_.reserve(__size); }) { + __keys_.reserve(__size); + } + } + + template + friend typename flat_set<_Key2, _Compare2, _KeyContainer2>::size_type + erase_if(flat_set<_Key2, _Compare2, _KeyContainer2>&, _Predicate); + + _KeyContainer __keys_; + _LIBCPP_NO_UNIQUE_ADDRESS key_compare __compare_; + + struct __key_equiv { + _LIBCPP_HIDE_FROM_ABI __key_equiv(key_compare __c) : __comp_(__c) {} + _LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const { + return !__comp_(__x, __y) && !__comp_(__y, __x); + } + key_compare __comp_; + }; +}; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(_KeyContainer, _Compare = _Compare()) -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(_KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(_KeyContainer, _Compare, _Allocator) -> flat_set; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare = _Compare()) + -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(sorted_unique_t, _KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare, _Allocator) + -> flat_set; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(_InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >, + class _Allocator = allocator, + class = __enable_if_t::value && __is_allocator<_Allocator>::value>> +flat_set(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> flat_set< + ranges::range_value_t<_Range>, + _Compare, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template ::value>> +flat_set(from_range_t, _Range&&, _Allocator) -> flat_set< + ranges::range_value_t<_Range>, + less>, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template +struct uses_allocator, _Allocator> + : bool_constant> {}; + + template + _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type + erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; + } + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FLAT_set_FLAT_SET_H diff --git a/libcxx/include/flat_set b/libcxx/include/flat_set new file mode 100644 index 000000000000000..d03645fafafdba0 --- /dev/null +++ b/libcxx/include/flat_set @@ -0,0 +1,59 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_FLAT_SET +#define _LIBCPP_FLAT_SET + +/* + Header synopsis + +#include // see [compare.syn] +#include // see [initializer.list.syn] + +namespace std { + // [flat.set], class template flat_set + template, class KeyContainer = vector> + class flat_set; + + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + + template + struct uses_allocator, Allocator>; + + // [flat.set.erasure], erasure for flat_set + template + typename flat_set::size_type + erase_if(flat_set& c, Predicate pred); +} +*/ + +#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +# include <__cxx03/__config> +#else +# include <__config> + +# if _LIBCPP_STD_VER >= 23 +# include <__flat_map/sorted_unique.h> +# include <__flat_set/flat_set.h> +# endif + +// for feature-test macros +# include + +// standard required includes +# include +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif +#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) + +#endif // _LIBCPP_FLAT_SET diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4bae02137b37b21..abc351d5923963d 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1263,6 +1263,17 @@ module std [system] { export * } + module flat_set { + module flat_set { + header "__flat_set/flat_set.h" + export std.vector.vector + export std.vector.fwd + } + + header "flat_set" + export * + } + module format { module buffer { header "__format/buffer.h" diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp new file mode 100644 index 000000000000000..204df1d681af1bc --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m; + ASSERT_SAME_TYPE(decltype(m.empty()), bool); + ASSERT_NOEXCEPT(m.empty()); + assert(m.empty()); + assert(std::as_const(m).empty()); + m = {1}; + assert(!m.empty()); + m.clear(); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp new file mode 100644 index 000000000000000..161fe533eabacb0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include + +void f() { + std::flat_set c; + c.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp new file mode 100644 index 000000000000000..cd7f424e00ece23 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type max_size() const noexcept; + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_allocator.h" +#include "test_macros.h" + +int main(int, char**) { + { + using A1 = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= 10); + LIBCPP_ASSERT(c.max_size() == 10); + } + { + using A = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + LIBCPP_ASSERT(c.max_size() == max_dist); + } + { + typedef std::flat_set C; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + assert(c.max_size() <= alloc_max_size(std::allocator())); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp new file mode 100644 index 000000000000000..7c156e95ecb1c86 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type size() const noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using M = std::flat_set, KeyContainer>; + using S = typename M::size_type; + { + const M m = {1, 1, 4, 5, 5}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 3); + } + { + const M m = {1}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 1); + } + { + const M m; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 0); + } + { + M m; + S s = 1000000; + for (auto i = 0u; i < s; ++i) { + m.emplace(i); + } + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == s); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp new file mode 100644 index 000000000000000..acc0817d7cac4d6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// explicit flat_set(const Allocator& a); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // explicit + using M = std::flat_set, std::vector>>; + + static_assert(std::is_constructible_v>); + static_assert(!std::is_convertible_v, M>); + } + { + using A = test_allocator; + using M = std::flat_set, std::vector>>; + M m(A(0, 5)); + assert(m.empty()); + assert(m.begin() == m.end()); + auto v = std::move(m).extract(); + assert(v.get_allocator().get_id() == 5); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp new file mode 100644 index 000000000000000..7f75f1e1611e3b4 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(initializer_list il); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m = {8, 10}; + assert(m.size() == 2); + m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + int expected[] = {1, 2, 3, 4, 5, 6}; + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + } + { + M m = {10, 8}; + assert(m.size() == 2); + m = {3}; + int expected[] = {3}; + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp new file mode 100644 index 000000000000000..b3bee18f5a936b1 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(const key_compare& comp); +// template +// flat_set(const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + auto m = std::flat_set(C(3)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(3)); + } + { + // The one-argument ctor is explicit. + using C = test_less; + static_assert(std::is_constructible_v, C>); + static_assert(!std::is_convertible_v>); + + static_assert(std::is_constructible_v, std::less>); + static_assert(!std::is_convertible_v, std::flat_set>); + } + { + using C = test_less; + using A1 = test_allocator; + auto m = std::flat_set>(C(4), A1(5)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + { + // explicit(false) + using C = test_less; + using A1 = test_allocator; + std::flat_set> m = {C(4), A1(5)}; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp new file mode 100644 index 000000000000000..3d1e6240c952e8c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -0,0 +1,158 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(container_type key_cont, const key_compare& comp = key_compare()); +// template +// flat_set(const container_type& key_cont, const Allocator& a); +// template +// flat_set(const container_type& key_cont, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(container_type) + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + + // explicit + static_assert(std::is_constructible_v&>); + static_assert(!ImplicitlyConstructible&>); + } + { + // flat_set(container_type) + // move-only + MoveOnly expected[] = {3, 2, 1}; + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks; + ks.push_back(1); + ks.push_back(3); + ks.push_back(2); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(container_type) + // container's allocator is used + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(5)); + } + { + // flat_set(container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + + // explicit + static_assert(std::is_constructible_v&, const C&>); + static_assert(!ImplicitlyConstructible&, const C&>); + } + { + // flat_set(container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(ks, A(4)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , const Allocator&) + // explicit(false) + using A = test_allocator; + using M = std::flat_set, std::deque>; + static_assert(ImplicitlyConstructible&, const A&>); + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + M m = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4), A(5)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + auto m_copy = m; + auto keys = std::move(m_copy).extract(); + assert(keys.get_allocator() == A(5)); + + // explicit(false) + static_assert(ImplicitlyConstructible&, const A&>); + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + keys = std::move(m2).extract(); + assert(keys.get_allocator() == A(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp new file mode 100644 index 000000000000000..f1dbc955e1b0de7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(-2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp new file mode 100644 index 000000000000000..59fb9d0a38366fe --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M(mo, test_allocator(3)); + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(3)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp new file mode 100644 index 000000000000000..169b469f3bca68b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& s); + +// Validate whether the container can be copy-assigned (move-assigned, swapped) +// with an ADL-hijacking operator& + +#include +#include + +#include "test_macros.h" +#include "operator_hijacker.h" + +void test() { + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp new file mode 100644 index 000000000000000..cdd5045f4bb9f7e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // test_allocator is not propagated + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M({{3, 4, 5}}, C(3), test_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + // other_allocator is propagated + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = M({3, 4, 5}, C(3), other_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + { + // comparator is copied and invariant is preserved + using M = std::flat_set>; + M mo = M({1, 2}, std::less()); + M m = M({1, 2}, std::greater()); + assert(m.key_comp()(2, 1) == true); + assert(m != mo); + m = mo; + assert(m.key_comp()(2, 1) == false); + assert(m == mo); + } + { + // self-assignment + using M = std::flat_set; + M m = {{1, 2}}; + m = static_cast(m); + assert((m == M{{1, 2}})); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp new file mode 100644 index 000000000000000..5db8c4ca7224665 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Test CTAD on cases where deduction should fail. + +#include +#include +#include +#include +#include + +struct NotAnAllocator { + friend bool operator<(NotAnAllocator, NotAnAllocator) { return false; } +}; + +template +concept CanDeductFlatSet = requires { std::flat_set{std::declval()...}; }; + +static_assert(CanDeductFlatSet, std::vector>); + +// cannot deduce Key and T from nothing +static_assert(!CanDeductFlatSet<>); + +// cannot deduce Key and T from just (KeyContainer), even if it's a container of pairs +static_assert(!CanDeductFlatSet>>); + +// cannot deduce Key and T from just (KeyContainer, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>>); + +// cannot deduce Key and T from just (Compare) +static_assert(!CanDeductFlatSet>); + +// cannot deduce Key and T from just (Compare, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>); + +// cannot deduce Key and T from just (Allocator) +static_assert(!CanDeductFlatSet>); + +// cannot convert from some arbitrary unrelated type +static_assert(!CanDeductFlatSet); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp new file mode 100644 index 000000000000000..612e64a7c42f23e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -0,0 +1,341 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "deduction_guides_sfinae_checks.h" +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_copy() { + { + std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set s(source); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s{source}; // braces instead of parens + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s(source, std::allocator()); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } +} + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(ks, vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(ks, vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_iter_iter() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m(std::begin(arr), std::end(arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) + static_assert(std::is_same_v>); + assert(s.size() == 3); + } +} + +void test_iter_iter_compare() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m(std::begin(arr), std::end(arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } +} + +void test_initializer_list() { + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } + { + using M = std::flat_set; + M m; + std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + assert(s[m] == m); + } +} + +void test_initializer_list_compare() { + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } +} + +void test_from_range() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(std::from_range, r); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +void test_from_range_compare() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(std::from_range, r, std::greater()); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +int main(int, char**) { + // Each test function also tests the sorted_unique-prefixed and allocator-suffixed overloads. + test_copy(); + test_containers(); + test_containers_compare(); + test_iter_iter(); + test_iter_iter_compare(); + test_initializer_list(); + test_initializer_list_compare(); + test_from_range(); + test_from_range_compare(); + + AssociativeContainerDeductionGuidesSfinaeAway>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp new file mode 100644 index 000000000000000..df8d6d885ee5246 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + const int expected[] = {1, 2, 3, INT_MAX}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + const int expected[] = {INT_MAX, 3, 2, 1}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +int main(int, char**) { + test_containers(); + test_containers_compare(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp new file mode 100644 index 000000000000000..64b0bfcb383a720 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + std::flat_set m; + assert(m.empty()); + } + { + // explicit(false) + std::flat_set m = {}; + assert(m.empty()); + } + { + std::flat_set>> m; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp().default_constructed_); + } + { + using A1 = explicit_allocator; + using A2 = explicit_allocator; + { + std::flat_set> m; + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + { + A1 a1; + std::flat_set> m(a1); + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp new file mode 100644 index 000000000000000..b4a3b6de205a31b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set() +// noexcept( +// is_nothrow_default_constructible_v && +// is_nothrow_default_constructible_v); + +// This tests a conforming extension + +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +int main(int, char**) { +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp new file mode 100644 index 000000000000000..c0d315c0ce74b4b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// ~flat_set(); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingDtorComp { + bool operator()(const auto&, const auto&) const; + ~ThrowingDtorComp() noexcept(false) {} +}; + +int main(int, char**) { + { + using C = std::flat_set; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::vector>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::deque>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(!std::is_nothrow_destructible_v); + C c; + } +#endif // _LIBCPP_VERSION + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp new file mode 100644 index 000000000000000..cd2319e91f760d9 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -0,0 +1,151 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(initializer_list il, const key_compare& comp = key_compare()); +// template +// flat_set(initializer_list il, const Alloc& a); +// template +// flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +#include "../../../test_compare.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + } + + int expected[] = {1, 2, 3, 5}; + { + // flat_set(initializer_list); + using M = std::flat_set; + std::initializer_list il = {5, 2, 2, 3, 1, 3}; + M m(il); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + // explicit(false) + using M = std::flat_set; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + using M = std::flat_set, std::deque>>; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + { + using A = explicit_allocator; + { + // flat_set(initializer_list); + // different comparator + using M = std::flat_set>; + M m = {1, 2, 3}; + assert(m.size() == 1); + LIBCPP_ASSERT(*m.begin() == 1); + assert(m.key_comp().default_constructed_); + } + { + // flat_set(initializer_list, const Allocator&); + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + } + { + // flat_set(initializer_list, const key_compare&); + using C = test_less; + using M = std::flat_set; + auto m = M({5, 2, 2, 3, 1, 3}, C(10)); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + assert(m.key_comp() == C(10)); + + // explicit(false) + M m2 = {{5, 2, 2, 1, 3, 3}, C(10)}; + assert(m2 == m); + assert(m2.key_comp() == C(10)); + } + { + // flat_set(initializer_list, const key_compare&); + // Sorting uses the comparator that was passed in + using M = std::flat_set, std::deque>>; + auto m = M({5, 2, 2, 1, 3, 1}, std::greater()); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + assert(m.key_comp()(2, 1) == true); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using A = explicit_allocator; + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, {}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp new file mode 100644 index 000000000000000..65eebc21a66c4cb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(InputIterator first, InputIterator last, const Allocator& a); +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(InputIterator , InputIterator) + // cpp17_input_iterator + using M = std::flat_set; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)}; + assert(m2 == m); + } + { + // flat_set(InputIterator , InputIterator) + // greater + using M = std::flat_set, std::deque>>; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(InputIterator , InputIterator) + // Test when the operands are of array type (also contiguous iterator type) + using M = std::flat_set, std::vector>>; + auto m = M(ar, ar); + assert(m.empty()); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&) + using C = test_less; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {ar, ar + 9, C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + auto m = M(ar, ar + 9, A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + M m = {ar, ar + 9, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {ar, ar + 9, {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp new file mode 100644 index 000000000000000..69b340ad09fe158 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A(7)); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A(7)); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().get_id() == test_alloc_base::moved_value); + } + { + using C = test_less; + using A = min_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A()); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A()); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A()); + } + { + // A moved-from flat_set maintains its class invariant in the presence of moved-from comparators. + using M = std::flat_set>; + M mo = M({1, 2, 3}, std::less()); + M m = std::move(mo); + assert(m.size() == 3); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.key_comp()(1, 2) == true); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + LIBCPP_ASSERT(m.key_comp()(1, 2) == true); + LIBCPP_ASSERT(mo.empty()); + mo.insert({1, 2, 3}); // insert has no preconditions + assert(m == mo); + } + { + // moved-from object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m1.size() == 0); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp new file mode 100644 index 000000000000000..fc7f68d8c967ad2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + int expected[] = {1, 2, 3}; + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + auto mo = M(expected, expected + 3, C(5), A(7)); + auto m = M(std::move(mo), A(3)); + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(3)); + assert(std::ranges::equal(keys, expected )); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A(7)); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2(std::move(m1), std::allocator{}); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp new file mode 100644 index 000000000000000..b16dc38dd402859 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{4, 5})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + m = std::move(mo); + assert((m == M{5, 4, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A()); + assert(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp new file mode 100644 index 000000000000000..50817f4be8a8125 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); +// Preserves the class invariant for the moved-from flat_set. + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +int main(int, char**) { + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp new file mode 100644 index 000000000000000..86f3568f0d67a6b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&& c) +// noexcept( +// is_nothrow_move_assignable::value && +// is_nothrow_move_assignable::value && +// is_nothrow_copy_assignable::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_macros.h" + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp new file mode 100644 index 000000000000000..17e4e40387606ce --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// flat_set(flat_set&& s); +// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +int main(int, char**) { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp new file mode 100644 index 000000000000000..49d1151fd8a993c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&) +// noexcept(is_nothrow_move_constructible::value && +// is_nothrow_move_constructible::value && +// is_nothrow_copy_constructible::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp new file mode 100644 index 000000000000000..785718d2eed333f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -0,0 +1,322 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +// Test various constructors with pmr + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // flat_set(const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::polymorphic_allocator pa = &mr; + auto m1 = M(pa); + assert(m1.empty()); + assert(std::move(m1).extract().get_allocator() == pa); + auto m2 = M(&mr); + assert(m2.empty()); + assert(std::move(m2).extract().get_allocator() == pa); + } + { + // flat_set(const key_compare& comp, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::greater()); + assert(vm[0] == M{}); + assert(vm[0].key_comp()(2, 1) == true); + assert(vm[0].value_comp()(2, 1) == true); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + // const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + assert(ks.get_allocator().resource() != &mr); + vm.emplace_back(ks); + assert(ks.size() == 9); // ks' value is unchanged, since it was an lvalue above + assert((vm[0] == M{1, 2, 3})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const flat_set&, const allocator_type&); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, C(5), &mr1); + M m = {mo, &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + auto keys = std::move(m).extract(); + assert((keys == std::pmr::vector{1, 2, 3})); + assert(keys.get_allocator().resource() == &mr2); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + auto keys2 = std::move(mo).extract(); + assert((keys2 == std::pmr::vector{1, 2, 3})); + assert(keys2.get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set&, const allocator_type&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::vector vs; + M m = {1, 2, 3}; + vs.push_back(m); + assert(vs[0] == m); + } + { + // flat_set& operator=(const flat_set& m); + // pmr allocator is not propagated + using M = std::flat_set, std::pmr::deque>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, &mr1); + M m = M({4, 5}, &mr2); + m = mo; + assert((m == M{1, 2, 3})); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // mo is unchanged + assert((mo == M{1, 2, 3})); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set& m); + using C = test_less; + std::pmr::monotonic_buffer_resource mr; + using M = std::flat_set>; + auto mo = M({1, 2, 3}, C(5), &mr); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert((m == M{1, 2, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator().resource() == std::pmr::get_default_resource()); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert((mo == M{1, 2, 3})); + auto kso = std::move(mo).extract(); + assert(kso.get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il, C(5)); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + assert(vm[0].key_comp() == C(5)); + } + { + // flat_set(InputIterator first, InputIterator last, const Allocator& a); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // cpp17 iterator + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(ar, ar); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(flat_set&&, const allocator_type&); + int expected[] = {1, 2, 3}; + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 3, 1, 2}, C(5), &mr1); + M m = {std::move(mo), &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + assert(std::equal(m.begin(), m.end(), expected, expected + 3)); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(flat_set&&, const allocator_type&); + using M = std::flat_set, std::pmr::deque>; + std::pmr::vector vs; + M m = {1, 3, 1, 2}; + vs.push_back(std::move(m)); + assert((std::move(vs[0]).extract() == std::pmr::deque{1, 2, 3})); + } + { + // flat_set& operator=(flat_set&&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = + M({"short", "very long string that definitely won't fit in the SSO buffer and therefore becomes empty on move"}, + &mr1); + M m = M({"don't care"}, &mr2); + m = std::move(mo); + assert(m.size() == 2); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.begin()->get_allocator().resource() == &mr2); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + mo.insert("foo"); + assert(mo.begin()->get_allocator().resource() == &mr1); + } + { + // flat_set(from_range_t, R&&, const Alloc&); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // input_range + using M = std::flat_set, std::pmr::vector>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(ar, ar)); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 2, 4, 10}; + vm.emplace_back(std::sorted_unique, ks); + assert(!ks.empty()); // it was an lvalue above + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, const container_type& key_cont,const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks({1, 2, 4, 10}, &mr); + vm.emplace_back(std::sorted_unique, ks); + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp new file mode 100644 index 000000000000000..bb9f99c228bfecc --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -0,0 +1,173 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// flat_set(from_range_t, R&&) +// template R> +// flat_set(from_range_t, R&&, const key_compare&) +// template R, class Alloc> +// flat_set(from_range_t, R&&, const Alloc&); +// template R, class Alloc> +// flat_set(from_range_t, R&&, const key_compare&, const Alloc&); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +// test constraint container-compatible-range + +template +using RangeOf = std::ranges::subrange; +using Set = std::flat_set; + +static_assert(std::is_constructible_v>); +static_assert(std::is_constructible_v>); +static_assert(!std::is_constructible_v>>); + +static_assert(std::is_constructible_v, std::less>); +static_assert(std::is_constructible_v, std::less>); +static_assert(!std::is_constructible_v>, std::less>); + +static_assert(std::is_constructible_v, std::allocator>); +static_assert(std::is_constructible_v, std::allocator>); +static_assert(!std::is_constructible_v>, std::allocator>); + +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert( + !std:: + is_constructible_v>, std::less, std::allocator>); + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(from_range_t, R&&) + // input_range && !common + using M = std::flat_set; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))}; + assert(m2 == m); + } + { + // flat_set(from_range_t, R&&) + // greater + using M = std::flat_set, std::deque>>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(from_range_t, R&&) + // contiguous range + using M = std::flat_set; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9)); + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(from_range_t, R&&, const key_compare&) + using C = test_less; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {std::from_range, R(ar, ar + 9), C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp new file mode 100644 index 000000000000000..2d442d49667bd07 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(sorted_unique_t, container_type key_cont, const key_compare& comp = key_compare()); +// +// template +// flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); +// template +// flat_set(sorted_unique_t, const container_type& key_cont, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, container_type) + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + auto ks2 = ks; + + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + + // explicit(false) + M m2 = {std::sorted_unique, std::move(ks2)}; + assert(m == m2); + } + { + // flat_set(sorted_unique_t, container_type) + // non-default container, comparator and allocator type + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks = {10, 4, 2, 1}; + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + } + { + // flat_set(sorted_unique_t, container_type) + // allocator copied into the containers + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + assert(std::move(m).extract().get_allocator() == A(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + + auto m = M(std::sorted_unique, ks, C(4)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, C(4)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 2, 4, 10}; + auto m = M(std::sorted_unique, ks, C(4), A(5)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + assert(M(m).extract().get_allocator() == A(5)); + + // explicit(false) + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + assert(std::move(m2).extract().get_allocator() == A(5)); + } + { + // flat_set(sorted_unique_t, container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, ks, A(6)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 4, 10})); + assert(M(m).extract().get_allocator() == A(6)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, A(6)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp new file mode 100644 index 000000000000000..01956a78c7f48dd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t s, initializer_list il, +// const key_compare& comp = key_compare()) +// template +// flat_set(sorted_unique_t, initializer_list il, const Alloc& a); +// template +// flat_set(sorted_unique_t, initializer_list il, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +std::initializer_list il = {1, 2, 4, 5}; + +const auto il1 = il; +const auto il2 = il; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + } + + { + // flat_set(sorted_unique_t, initializer_list); + using M = std::flat_set; + auto m = M(std::sorted_unique, il1); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, il1}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + using M = std::flat_set>; + auto m = M(std::sorted_unique, il1, std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, il1, std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + std::initializer_list il4{5, 4, 2, 1}; + auto m = M(std::sorted_unique, il4, std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, initializer_list, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + auto m = M(std::sorted_unique, il2, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, il2, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(std::sorted_unique, il2, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {std::sorted_unique, il2, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp new file mode 100644 index 000000000000000..b5229a84dd51333 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // cpp17_input_iterator + using M = std::flat_set; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // cpp_17_input_iterator + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + int ar[] = {5, 4, 2, 1}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[1] = {42}; + auto m = M(std::sorted_unique, ar, ar, C(5)); + assert(m.empty()); + assert(m.key_comp() == C(5)); + } + { + // flat_set(sorted_unique_t, InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, ar, ar + 4, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + int ar[] = {1, 2, 4, 5}; + M m = {std::sorted_unique, ar, ar + 4, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp new file mode 100644 index 000000000000000..134db83aef3cad2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "min_allocator.h" + +// Verify that `flat_set` (like `set`) does NOT support std::erase. +// +template +concept HasStdErase = requires(S& s, typename S::value_type x) { std::erase(s, x); }; +static_assert(HasStdErase>); +static_assert(!HasStdErase>); + +template +M make(std::initializer_list vals) { + M ret; + for (int v : vals) + ret.emplace(v); + return ret; +} + +template +void test0( + std::initializer_list vals, Pred p, std::initializer_list expected, std::size_t expected_erased_count) { + M s = make(vals); + ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p))); + assert(expected_erased_count == std::erase_if(s, p)); + assert(s == make(expected)); +} + +template +void test() { + // Test all the plausible signatures for this predicate. + auto is1 = [](typename S::const_reference v) { return v == 1; }; + auto is2 = [](typename S::value_type v) { return v == 2; }; + auto is3 = [](const typename S::value_type& v) { return v == 3; }; + auto is4 = [](auto v) { return v == 4; }; + auto True = [](const auto&) { return true; }; + auto False = [](auto&&) { return false; }; + + test0({}, is1, {}, 0); + + test0({1}, is1, {}, 1); + test0({1}, is2, {1}, 0); + + test0({1, 2}, is1, {2}, 1); + test0({1, 2}, is2, {1}, 1); + test0({1, 2}, is3, {1, 2}, 0); + + test0({1, 2, 3}, is1, {2, 3}, 1); + test0({1, 2, 3}, is2, {1, 3}, 1); + test0({1, 2, 3}, is3, {1, 2}, 1); + test0({1, 2, 3}, is4, {1, 2, 3}, 0); + + test0({1, 2, 3}, True, {}, 3); + test0({1, 2, 3}, False, {1, 2, 3}, 0); +} + +int main(int, char**) { + test>(); + test, std::vector>>>(); + test, std::vector>>>(); + test, std::deque>>>(); + test, std::deque>>>(); + test>(); + test>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp new file mode 100644 index 000000000000000..6bbe1ad4f016705 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -0,0 +1,128 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); +// If any member function in [flat.set.defn] exits via an exception, the invariant is restored. +// (This is not a member function, but let's respect the invariant anyway.) + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct Counter { + int c1, c2, throws; + void tick() { + c1 -= 1; + if (c1 == 0) { + c1 = c2; + throws += 1; + throw 42; + } + } +}; +Counter g_counter = {0, 0, 0}; + +struct ThrowingAssignment { + ThrowingAssignment(int i) : i_(i) {} + ThrowingAssignment(const ThrowingAssignment&) = default; + ThrowingAssignment& operator=(const ThrowingAssignment& rhs) { + g_counter.tick(); + i_ = rhs.i_; + g_counter.tick(); + return *this; + } + operator int() const { return i_; } + int i_; +}; + +struct ThrowingComparator { + bool operator()(const ThrowingAssignment& a, const ThrowingAssignment& b) const { + g_counter.tick(); + return a.i_ < b.i_; + } +}; + +struct ErasurePredicate { + bool operator()(const auto& x) const { return (3 <= x && x <= 5); } +}; + +int main(int, char**) { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + { + using M = std::flat_set; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + M m = M({1, 2, 3, 4, 5, 6, 7, 8}); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + + { + using M = std::flat_set>; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + std::deque container = {5, 6, 7, 8}; + container.insert(container.begin(), {1, 2, 3, 4}); + M m = M(std::move(container)); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp new file mode 100644 index 000000000000000..c07297a141ad109 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator begin() noexcept; +// const_iterator begin() const noexcept +// iterator end() noexcept; +// const_iterator end() const noexcept; +// +// const_iterator cbegin() const noexcept; +// const_iterator cend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.begin()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cbegin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.begin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(m.end()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cend()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.end()), typename M::const_iterator); + static_assert(noexcept(m.begin())); + static_assert(noexcept(cm.begin())); + static_assert(noexcept(m.cbegin())); + static_assert(noexcept(m.end())); + static_assert(noexcept(cm.end())); + static_assert(noexcept(m.cend())); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(std::distance(cm.begin(), cm.end()) == 4); + assert(std::distance(m.cbegin(), m.cend()) == 4); + typename M::iterator i; // default-construct + i = m.begin(); // move-assignment + typename M::const_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 1; j <= 4; ++j, ++i) { // pre-increment + assert(*i == j); // operator* + } + assert(i == m.end()); + for (int j = 4; j >= 1; --j) { + --i; // pre-decrement + assert((*i) == j); + } + assert(i == m.begin()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // N3644 testing + using C = std::flat_set; + C::iterator ii1{}, ii2{}; + C::iterator ii4 = ii1; + C::const_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp new file mode 100644 index 000000000000000..29441dcc57d40e4 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set iterators should be C++20 random access iterators + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using KI = typename KeyContainer::iterator; + using I = M::iterator; + using CI = M::const_iterator; + using RI = M::reverse_iterator; + using CRI = M::const_reverse_iterator; + + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + + M m = {1, 2, 3, 4}; + + I i1 = m.begin(); + I i2 = m.begin() + 1; + + assert(i1 == i1); + assert(!(i1 != i1)); + assert(i1 != i2); + assert(!(i1 == i2)); + assert(i1 < i2); + assert(!(i1 < i1)); + assert(i1 <= i1); + assert(i1 <= i2); + assert(!(i2 <= i1)); + assert(i2 > i1); + assert(!(i2 > i2)); + assert(i2 >= i1); + assert(i2 >= i2); + assert(!(i1 >= i2)); + + CI ci1 = m.cbegin(); + CI ci2 = m.cbegin() + 1; + assert(ci1 == ci1); + assert(!(ci1 != ci1)); + assert(ci1 != ci2); + assert(!(ci1 == ci2)); + assert(ci1 < ci2); + assert(!(ci1 < ci1)); + assert(ci1 <= ci1); + assert(ci1 <= ci2); + assert(!(ci2 <= ci1)); + assert(ci2 > ci1); + assert(!(ci2 > ci2)); + assert(ci2 >= ci1); + assert(ci2 >= ci2); + assert(!(ci1 >= ci2)); + + RI ri1 = m.rbegin(); + RI ri2 = m.rbegin() + 1; + assert(ri1 == ri1); + assert(!(ri1 != ri1)); + assert(ri1 != ri2); + assert(!(ri1 == ri2)); + assert(ri1 < ri2); + assert(!(ri1 < ri1)); + assert(ri1 <= ri1); + assert(ri1 <= ri2); + assert(!(ri2 <= ri1)); + assert(ri2 > ri1); + assert(!(ri2 > ri2)); + assert(ri2 >= ri1); + assert(ri2 >= ri2); + assert(!(ri1 >= ri2)); + + CRI cri1 = m.crbegin(); + CRI cri2 = m.crbegin() + 1; + assert(cri1 == cri1); + assert(!(cri1 != cri1)); + assert(cri1 != cri2); + assert(!(cri1 == cri2)); + assert(cri1 < cri2); + assert(!(cri1 < cri1)); + assert(cri1 <= cri1); + assert(cri1 <= cri2); + assert(!(cri2 <= cri1)); + assert(cri2 > cri1); + assert(!(cri2 > cri2)); + assert(cri2 >= cri1); + assert(cri2 >= cri2); + assert(!(cri1 >= cri2)); + + if constexpr (std::three_way_comparable) { + static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::same_as I()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as RI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + + assert(i1 <=> i1 == std::strong_ordering::equivalent); + assert(i1 <=> i2 == std::strong_ordering::less); + assert(i2 <=> i1 == std::strong_ordering::greater); + + assert(ci1 <=> ci1 == std::strong_ordering::equivalent); + assert(ci1 <=> ci2 == std::strong_ordering::less); + assert(ci2 <=> ci1 == std::strong_ordering::greater); + + assert(ri1 <=> ri1 == std::strong_ordering::equivalent); + assert(ri1 <=> ri2 == std::strong_ordering::less); + assert(ri2 <=> ri1 == std::strong_ordering::greater); + + assert(cri1 <=> cri1 == std::strong_ordering::equivalent); + assert(cri1 <=> cri2 == std::strong_ordering::less); + assert(cri2 <=> cri1 == std::strong_ordering::greater); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp new file mode 100644 index 000000000000000..35b45b6e797233e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator, const_iterator, reverse_iterator, const_reverse_iterator + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + using I = C::iterator; + using CI = C::const_iterator; + using RI = C::reverse_iterator; + using CRI = C::const_reverse_iterator; + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp new file mode 100644 index 000000000000000..4ec64e706b70218 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include +#include +#include +#include +#include +#include "MinSequenceContainer.h" +#include "min_allocator.h" + +template +void test() { + { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + + static_assert(std::same_as, typename C::iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(std::ranges::viewable_range); + + static_assert(std::same_as, typename C::const_iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(!std::ranges::viewable_range); + } +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp new file mode 100644 index 000000000000000..a16383cdcf53830 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// reverse_iterator rbegin() noexcept; +// const_reverse_iterator rbegin() const noexcept; +// reverse_iterator rend() noexcept; +// const_reverse_iterator rend() const noexcept; +// +// const_reverse_iterator crbegin() const noexcept; +// const_reverse_iterator crend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include + +#include "test_macros.h" +#include + +int main(int, char**) { + { + using M = std::flat_set, std::deque>; + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.rbegin()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.rend()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crend()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rend()), M::const_reverse_iterator); + static_assert(noexcept(m.rbegin())); + static_assert(noexcept(cm.rbegin())); + static_assert(noexcept(m.crbegin())); + static_assert(noexcept(m.rend())); + static_assert(noexcept(cm.rend())); + static_assert(noexcept(m.crend())); + assert(m.size() == 4); + assert(std::distance(m.rbegin(), m.rend()) == 4); + assert(std::distance(cm.rbegin(), cm.rend()) == 4); + assert(std::distance(m.crbegin(), m.crend()) == 4); + assert(std::distance(cm.crbegin(), cm.crend()) == 4); + M::reverse_iterator i; // default-construct + ASSERT_SAME_TYPE(decltype(*i), const int&); + i = m.rbegin(); // move-assignment + M::const_reverse_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 4; j >= 1; --j, ++i) { // pre-increment + assert(*i == j); + } + assert(i == m.rend()); + for (int j = 1; j <= 4; ++j) { + --i; // pre-decrement + assert(*i == j); + } + assert(i == m.rbegin()); + } + { + // N3644 testing + using C = std::flat_set; + C::reverse_iterator ii1{}, ii2{}; + C::reverse_iterator ii4 = ii1; + C::const_reverse_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp new file mode 100644 index 000000000000000..221a13fa057577a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// void clear() noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// test noexcept + +template +concept NoExceptClear = requires(T t) { + { t.clear() } noexcept; +}; + +static_assert(NoExceptClear>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptClear, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4, 5}; + assert(m.size() == 5); + ASSERT_NOEXCEPT(m.clear()); + ASSERT_SAME_TYPE(decltype(m.clear()), void); + m.clear(); + assert(m.size() == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp new file mode 100644 index 000000000000000..95f7a3c5f5d34a2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -0,0 +1,141 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// pair emplace(Args&&... args); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the begin + M m = {3, 5, 6, 7}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted in the middle + M m = {0, 1, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the end + M m = {0, 1}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } + { + // key already exists and original at the begin + M m = {2, 3, 5, 6}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original in the middle + M m = {0, 2, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 1); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original at the end + M m = {0, 1, 2}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace()), R); + R r = m.emplace(2, 0.0); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace(1, 3.5); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace(1, 3.5); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp new file mode 100644 index 000000000000000..de855d5e5c30097 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// iterator emplace_hint(const_iterator position, Args&&... args); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace_hint(m.end(), typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + } + { + // hints correct at the begin + M m = {3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints correct at the end + M m = {0, 1}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct but key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the begin + M m = {1, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrectly in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 1; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the end + M m = {0, 3}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrect and key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace_hint(m.cbegin())), R); + R r = m.emplace_hint(m.end(), 2, 0.0); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp new file mode 100644 index 000000000000000..386af04d26e9a2e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(iterator position); +// iterator erase(const_iterator position); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(std::next(m.cbegin(), 3)); + assert(m.size() == 7); + assert(i1 == std::next(m.begin(), 3)); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 5); + assert(*std::next(m.begin(), 4) == 6); + assert(*std::next(m.begin(), 5) == 7); + assert(*std::next(m.begin(), 6) == 8); + + std::same_as decltype(auto) i2 = m.erase(std::next(m.begin(), 0)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 5)); + assert(m.size() == 5); + assert(i3 == m.end()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + + std::same_as decltype(auto) i4 = m.erase(std::next(m.begin(), 1)); + assert(m.size() == 4); + assert(i4 == std::next(m.begin())); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 6); + assert(*std::next(m.begin(), 3) == 7); + + std::same_as decltype(auto) i5 = m.erase(std::next(m.cbegin(), 2)); + assert(m.size() == 3); + assert(i5 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 7); + + std::same_as decltype(auto) i6 = m.erase(std::next(m.begin(), 2)); + assert(m.size() == 2); + assert(i6 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + + std::same_as decltype(auto) i7 = m.erase(std::next(m.cbegin(), 0)); + assert(m.size() == 1); + assert(i7 == std::next(m.begin(), 0)); + assert(*m.begin() == 5); + + std::same_as decltype(auto) i8 = m.erase(m.begin()); + assert(m.size() == 0); + assert(i8 == m.begin()); + assert(i8 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp new file mode 100644 index 000000000000000..7416977844e5df2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(const_iterator first, const_iterator last); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(m.cbegin(), m.cbegin()); + assert(m.size() == 8); + assert(i1 == m.begin()); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 4); + assert(*std::next(m.begin(), 4) == 5); + assert(*std::next(m.begin(), 5) == 6); + assert(*std::next(m.begin(), 6) == 7); + assert(*std::next(m.begin(), 7) == 8); + + std::same_as decltype(auto) i2 = m.erase(m.cbegin(), std::next(m.cbegin(), 2)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 2), std::next(m.cbegin(), 6)); + assert(m.size() == 2); + assert(i3 == std::next(m.begin(), 2)); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + + std::same_as decltype(auto) i4 = m.erase(m.cbegin(), m.cend()); + assert(m.size() == 0); + assert(i4 == m.begin()); + assert(i4 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp new file mode 100644 index 000000000000000..25d4f4af19608b4 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(const key_type& k); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template > +void test() { + using M = std::flat_set; + + auto make = [](std::initializer_list il) { + M m; + for (int i : il) { + m.emplace(i); + } + return m; + }; + M m = make({1, 2, 3, 4, 5, 6, 7, 8}); + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(9); + assert(n == 0); + assert(m == make({1, 2, 3, 4, 5, 6, 7, 8})); + n = m.erase(4); + assert(n == 1); + assert(m == make({1, 2, 3, 5, 6, 7, 8})); + n = m.erase(1); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7, 8})); + n = m.erase(8); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7})); + n = m.erase(3); + assert(n == 1); + assert(m == make({2, 5, 6, 7})); + n = m.erase(4); + assert(n == 0); + assert(m == make({2, 5, 6, 7})); + n = m.erase(6); + assert(n == 1); + assert(m == make({2, 5, 7})); + n = m.erase(7); + assert(n == 1); + assert(m == make({2, 5})); + n = m.erase(2); + assert(n == 1); + assert(m == make({5})); + n = m.erase(5); + assert(n == 1); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test, std::greater<>>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp new file mode 100644 index 000000000000000..cbf7cac603806d7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(K&& k); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanErase = requires(M m, Transparent k) { m.erase(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanErase); +static_assert(!CanErase); +static_assert(!CanErase); +static_assert(!CanErase); + +template +struct HeterogeneousKey { + explicit HeterogeneousKey(Key key, It it) : key_(key), it_(it) {} + operator It() && { return it_; } + auto operator<=>(Key key) const { return key_ <=> key; } + friend bool operator<(const HeterogeneousKey&, const HeterogeneousKey&) { + assert(false); + return false; + } + Key key_; + It it_; +}; + +template +void test_simple() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(3); // erase(K&&) [with K=int] + assert(n == 1); + assert((m == M{1, 2, 4})); + typename M::key_type lvalue = 2; + n = m.erase(lvalue); // erase(K&&) [with K=int&] + assert(n == 1); + assert((m == M{1, 4})); + const typename M::key_type const_lvalue = 1; + n = m.erase(const_lvalue); // erase(const key_type&) + assert(n == 1); + assert((m == M{4})); +} + +template +void test_transparent_comparator() { + using M = std::flat_set; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.erase(Transparent{"abc"})), typename M::size_type); + + auto n = m.erase(Transparent{"epsilon"}); + assert(n == 1); + + M expected = {"alpha", "beta", "eta", "gamma"}; + assert(m == expected); + + auto n2 = m.erase(Transparent{"aaa"}); + assert(n2 == 0); + assert(m == expected); +} + +int main(int, char**) { + test_simple>(); + test_simple>(); + test_simple>(); + test_simple>>(); + + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>>(); + + { + // P2077's HeterogeneousKey example + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.erase(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp new file mode 100644 index 000000000000000..c3bbffabb90a08f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// containers extract() &&; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanExtract = requires(T&& t) { std::forward(t).extract(); }; + +static_assert(CanExtract&&>); +static_assert(!CanExtract&>); +static_assert(!CanExtract const&>); +static_assert(!CanExtract const&&>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + M m = M({1, 2, 3}); + + std::same_as auto keys = std::move(m).extract(); + + auto expected_keys = {1, 2, 3}; + assert(std::ranges::equal(keys, expected_keys)); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // extracted object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m = M({1, 2, 3}); + std::same_as auto keys = std::move(m).extract(); + assert(keys.size() == 3); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); + } + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + auto c = std::move(m).extract(); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we try to erase the key after value emplacement failure. + // and after erasure failure, we clear the flat_set + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp new file mode 100644 index 000000000000000..c0ddadc30069872 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair insert(const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using VT = typename M::value_type; + M m; + + const VT v1(2); + std::same_as decltype(auto) r = m.insert(v1); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + + const VT v2(1); + r = m.insert(v2); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == 1); + + const VT v3(3); + r = m.insert(v3); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); + + const VT v4(3); + r = m.insert(v4); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp new file mode 100644 index 000000000000000..7381514a70eabbb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; + + M m = {1,1,1,3,3,3}; + m.insert({ + 4, + 4, + 4, + 1, + 1, + 1, + 2, + 2, + 2, + }); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(*m.begin() == V(1)); + assert(*std::next(m.begin()) == V(2)); + assert(*std::next(m.begin(), 2) == V(3)); + assert(*std::next(m.begin(), 3) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp new file mode 100644 index 000000000000000..c343d53a62215a8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator insert(const_iterator position, const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = typename M::iterator; + using VT = typename M::value_type; + + M m; + const VT v1(2); + std::same_as decltype(auto) r = m.insert(m.end(), v1); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + + const VT v2(1); + r = m.insert(m.end(), v2); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == 1); + + const VT v3(3); + r = m.insert(m.end(), v3); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); + + const VT v4(3); + r = m.insert(m.end(), v4); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp new file mode 100644 index 000000000000000..d20a8ef8fdd92d8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + + int ar1[] = { + 2, + 2, + 2, + 1, + 1, + 1, + 3, + 3, + 3, + }; + int ar2[] = { + 4, + 4, + 4, + 1, + 1, + 1, + 0, + 0, + 0, + }; + + M m; + m.insert(cpp17_input_iterator(ar1), cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(cpp17_input_iterator(ar2), cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp new file mode 100644 index 000000000000000..84b6c7fc1d34f62 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// +// iterator insert(const_iterator position, value_type&&); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "../helpers.h" +#include "test_macros.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + using R = typename M::iterator; + M m; + std::same_as decltype(auto) r = m.insert(m.end(), V(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == V(2)); + + r = m.insert(m.end(), V(1)); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == V(1)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp new file mode 100644 index 000000000000000..536307252c64058 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// void insert_range(R&& rg); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "MoveOnly.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint container-compatible-range +template +concept CanInsertRange = requires(M m, R&& r) { m.insert_range(std::forward(r)); }; + +using Set = std::flat_set; + +static_assert(CanInsertRange>); +static_assert(CanInsertRange>); +static_assert(!CanInsertRange*>>); +static_assert(!CanInsertRange*>>); + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using M = std::flat_set, KeyContainer>; + using It = forward_iterator; + M m = {10, 8, 5, 2, 1}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), It(ar + 6)}; + static_assert(std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9, 10})); + } + { + using M = std::flat_set, KeyContainer>; + using It = cpp20_input_iterator; + M m = {8, 5, 3, 2}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), sentinel_wrapper(It(ar + 6))}; + static_assert(!std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9})); + } + { + // The "uniquing" part uses the comparator, not operator==. + struct ModTen { + bool operator()(int a, int b) const { return (a % 10) < (b % 10); } + }; + using M = std::flat_set; + M m = {21, 43, 15, 37}; + int ar[] = {33, 18, 55, 18, 42}; + m.insert_range(ar); + assert((m == M{21, 42, 43, 15, 37, 18})); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // Items are forwarded correctly from the input range (P2767). + MoveOnly a[] = {3, 1, 4, 1, 5}; + std::flat_set m; + m.insert_range(a | std::views::as_rvalue); + MoveOnly expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + // The element type of the range doesn't need to be std::pair (P2767). + int pa[] = {3, 1, 4, 1, 5}; + std::deque> a(pa, pa + 5); + std::flat_set m; + m.insert_range(a); + int expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp new file mode 100644 index 000000000000000..7d95f0521eb1f67 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// pair insert( value_type&& v); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + using R = std::pair; + using V = typename M::value_type; + + M m; + std::same_as decltype(auto) r = m.insert(V(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == V(2)); + + r = m.insert(V(1)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == V(1)); + + r = m.insert(V(3)); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); + + r = m.insert(V(3)); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp new file mode 100644 index 000000000000000..fa5bf86830daecd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(sorted_unique_t, initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + M m = {1, 1, 1, 3, 3, 3}; + m.insert(std::sorted_unique, {0, 1, 2, 4}); + assert(m.size() == 5); + assert(std::distance(m.begin(), m.end()) == 5); + assert(*m.begin() == V(0)); + assert(*std::next(m.begin()) == V(1)); + assert(*std::next(m.begin(), 2) == V(2)); + assert(*std::next(m.begin(), 3) == V(3)); + assert(*std::next(m.begin(), 4) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp new file mode 100644 index 000000000000000..ef7b8391cee33c1 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(sorted_unique_t, InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + int ar1[] = {1, 2, 3}; + + int ar2[] = {0, 2, 4}; + + M m; + m.insert(std::sorted_unique, + cpp17_input_iterator(ar1), + cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(std::sorted_unique, + cpp17_input_iterator(ar2), + cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp new file mode 100644 index 000000000000000..72d7261a1825477 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -0,0 +1,169 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair insert(P&& x); +// template iterator insert(const_iterator hint, P&& x); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// Constraints: is_constructible_v is true. +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; +using Iter = Set::const_iterator; + +static_assert(CanInsert); +static_assert(CanInsert); +static_assert(!CanInsert); +static_assert(!CanInsert); + +static int expensive_comparisons = 0; +static int cheap_comparisons = 0; + +struct CompareCounter { + int i_ = 0; + CompareCounter(int i) : i_(i) {} + friend auto operator<=>(const CompareCounter& x, const CompareCounter& y) { + expensive_comparisons += 1; + return x.i_ <=> y.i_; + } + bool operator==(const CompareCounter&) const = default; + friend auto operator<=>(const CompareCounter& x, int y) { + cheap_comparisons += 1; + return x.i_ <=> y; + } +}; + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + const int expected[] = {1, 2, 3, 4, 5}; + { + // insert(P&&) + // Unlike flat_set, here we can't use key_compare to compare value_type versus P, + // so we must eagerly convert to value_type. + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, P&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // insert(value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens last + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // emplace(Args&&...) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.emplace(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // no ambiguity between insert(pos, P&&) and insert(first, last) + using M = std::flat_set; + struct Evil { + operator M::value_type() const; + operator M::const_iterator() const; + }; + std::flat_set m; + ASSERT_SAME_TYPE(decltype(m.insert(Evil())), std::pair); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); + } + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(t); + }; + test_emplace_exception_guarantee(insert_func); + } + { + auto insert_func_iter = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(m.begin(), t); + }; + test_emplace_exception_guarantee(insert_func_iter); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp new file mode 100644 index 000000000000000..49cb6eb6163c903 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void replace(container_type&& key_cont); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanReplace = requires(T t, Args&&... args) { t.replace(std::forward(args)...); }; + +using Set = std::flat_set; +static_assert(CanReplace>); +static_assert(!CanReplace&>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = M({1, 2, 3}); + KeyContainer new_keys = {7, 8}; + auto expected_keys = new_keys; + m.replace(std::move(new_keys)); + assert(m.size() == 2); + assert(std::ranges::equal(m, expected_keys)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp new file mode 100644 index 000000000000000..23a2dc85989bb7f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// `check_assertion.h` requires Unix headers and regex support. +// REQUIRES: has-unix-headers +// UNSUPPORTED: no-localization +// UNSUPPORTED: no-exceptions + +// + +// void swap(flat_set& y) noexcept; +// friend void swap(flat_set& x, flat_set& y) noexcept + +// Test that std::terminate is called if any exception is thrown during swap + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../helpers.h" +#include "check_assertion.h" + +template +void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) { + { + // key swap throws + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m1, m2; + m1.emplace(1); + m1.emplace(2); + m2.emplace(3); + m2.emplace(4); + // swap is noexcept + EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); }); + } +} + +int main(int, char**) { + { + auto swap_func = [](auto& m1, auto& m2) { swap(m1, m2); }; + test_swap_exception_guarantee(swap_func); + } + + { + auto swap_func = [](auto& m1, auto& m2) { m1.swap(m2); }; + test_swap_exception_guarantee(swap_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp new file mode 100644 index 000000000000000..bc7baa67e52a599 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend void swap(flat_set& x, flat_set& y) noexcept + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptAdlSwap = requires(T t1, T t2) { + { swap(t1, t2) } noexcept; +}; + +static_assert(NoExceptAdlSwap>); + +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptAdlSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp new file mode 100644 index 000000000000000..b0b06a9499efc7a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void swap(flat_set& y) noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptMemberSwap = requires(T t1, T t2) { + { t1.swap(t2) } noexcept; +}; + +static_assert(NoExceptMemberSwap>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptMemberSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp new file mode 100644 index 000000000000000..971b5e1c338dd11 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// key_compare key_comp() const; +// value_compare value_comp() const; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + { + using M = std::flat_set; + using Comp = std::less; // the default + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + { + using Comp = std::function; + using M = std::flat_set; + Comp comp = std::greater(); + M m({}, comp); + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(!kc(1, 2)); + assert(kc(2, 1)); + auto vc = m.value_comp(); + assert(!vc(1, 2)); + assert(vc(2, 1)); + } + { + using Comp = std::less<>; + using M = std::flat_set; + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + auto a = std::make_pair(1, 2); + ASSERT_SAME_TYPE(decltype(vc(a, a)), bool); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp new file mode 100644 index 000000000000000..b14da66f611301e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// bool contains(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp new file mode 100644 index 000000000000000..507560608952b01 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template bool contains(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanContains = requires(M m, Transparent k) { m.contains(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanContains); +static_assert(CanContains); +static_assert(!CanContains); +static_assert(!CanContains); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.contains(Transparent{"abc"})), bool); + ASSERT_SAME_TYPE(decltype(std::as_const(m).contains(Transparent{"b"})), bool); + assert(m.contains(Transparent{"alpha"}) == true); + assert(m.contains(Transparent{"beta"}) == true); + assert(m.contains(Transparent{"epsilon"}) == true); + assert(m.contains(Transparent{"eta"}) == true); + assert(m.contains(Transparent{"gamma"}) == true); + assert(m.contains(Transparent{"al"}) == false); + assert(m.contains(Transparent{""}) == false); + assert(m.contains(Transparent{"g"}) == false); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto b = m.contains(Transparent{3}); + assert(b); + assert(transparent_used); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp new file mode 100644 index 000000000000000..478f615358b6068 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type count(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using S = typename KeyContainer::size_type; + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp new file mode 100644 index 000000000000000..b591258f74399c8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template size_type count(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanCount = requires(M m, Transparent k) { m.count(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanCount); +static_assert(CanCount); +static_assert(!CanCount); +static_assert(!CanCount); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.count(Transparent{"abc"})), typename M::size_type); + ASSERT_SAME_TYPE(decltype(std::as_const(m).count(Transparent{"b"})), typename M::size_type); + assert(m.count(Transparent{"alpha"}) == 1); + assert(m.count(Transparent{"beta"}) == 1); + assert(m.count(Transparent{"epsilon"}) == 1); + assert(m.count(Transparent{"eta"}) == 1); + assert(m.count(Transparent{"gamma"}) == 1); + assert(m.count(Transparent{"al"}) == 0); + assert(m.count(Transparent{""}) == 0); + assert(m.count(Transparent{"g"}) == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.count(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp new file mode 100644 index 000000000000000..a088b7fee17d2ca --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair equal_range(const key_type& k); +// pair equal_range(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin, begin)); + assert(m.equal_range(1) == std::pair(begin, begin + 1)); + assert(m.equal_range(2) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(3) == std::pair(begin + 2, begin + 2)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(6) == std::pair(begin + 4, begin + 4)); + assert(m.equal_range(7) == std::pair(begin + 4, begin + 4)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin() + 4, m.cbegin() + 5)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin() + 5, m.cbegin() + 5)); + } + + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin + 5, begin + 5)); + assert(m.equal_range(1) == std::pair(begin + 4, begin + 5)); + assert(m.equal_range(2) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(3) == std::pair(begin + 3, begin + 3)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(6) == std::pair(begin + 1, begin + 1)); + assert(m.equal_range(7) == std::pair(begin + 1, begin + 1)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin(), m.cbegin() + 1)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin(), m.cbegin())); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp new file mode 100644 index 000000000000000..ede5d91e19b9fdd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair equal_range(const K& x); +// template pair equal_range(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanEqualRange = requires(M m, Transparent k) { m.equal_range(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanEqualRange); +static_assert(CanEqualRange); +static_assert(!CanEqualRange); +static_assert(!CanEqualRange); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + using R = std::pair; + using CR = std::pair; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.equal_range(Transparent{"abc"})), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(Transparent{"b"})), CR); + + auto test_found = [&](auto&& map, const std::string& expected_key) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(last - first == 1); + assert(*first == expected_key); + }; + + auto test_not_found = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(first == last); + assert(first - m.begin() == expected_offset); + }; + + test_found(m, "alpha"); + test_found(m, "beta"); + test_found(m, "epsilon"); + test_found(m, "eta"); + test_found(m, "gamma"); + test_found(cm, "alpha"); + test_found(cm, "beta"); + test_found(cm, "epsilon"); + test_found(cm, "eta"); + test_found(cm, "gamma"); + + test_not_found(m, "charlie", 2); + test_not_found(m, "aaa", 0); + test_not_found(m, "zzz", 5); + test_not_found(cm, "charlie", 2); + test_not_found(cm, "aaa", 0); + test_not_found(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto p = m.equal_range(Transparent{3}); + assert(p.first != p.second); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp new file mode 100644 index 000000000000000..cf0dd2d1dd831c8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator find(const key_type& k); +// const_iterator find(const key_type& k) const; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.find(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(0)), typename M::const_iterator); + assert(m.find(0) == m.end()); + assert(m.find(1) == m.begin()); + assert(m.find(2) == m.begin() + 1); + assert(m.find(3) == m.end()); + assert(m.find(4) == m.begin() + 2); + assert(m.find(5) == m.begin() + 3); + assert(m.find(6) == m.end()); + assert(m.find(7) == m.end()); + assert(std::as_const(m).find(8) == m.begin() + 4); + assert(std::as_const(m).find(9) == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp new file mode 100644 index 000000000000000..730a57b0a6cb855 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator find(const K& x); +// template const_iterator find(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanFind = requires(M m, Transparent k) { m.find(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanFind); +static_assert(CanFind); +static_assert(!CanFind); +static_assert(!CanFind); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.find(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(Transparent{"b"})), typename M::const_iterator); + + auto test_find = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.find(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_find(m, "alpha", 0); + test_find(m, "beta", 1); + test_find(m, "epsilon", 2); + test_find(m, "eta", 3); + test_find(m, "gamma", 4); + test_find(m, "charlie", 5); + test_find(m, "aaa", 5); + test_find(m, "zzz", 5); + test_find(cm, "alpha", 0); + test_find(cm, "beta", 1); + test_find(cm, "epsilon", 2); + test_find(cm, "eta", 3); + test_find(cm, "gamma", 4); + test_find(cm, "charlie", 5); + test_find(cm, "aaa", 5); + test_find(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.find(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp new file mode 100644 index 000000000000000..093c32e537ed35f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator lower_bound(const key_type& k); +// const_iterator lower_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.begin()); + assert(m.lower_bound(1) == m.begin()); + assert(m.lower_bound(2) == m.begin() + 1); + assert(m.lower_bound(3) == m.begin() + 2); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 3); + assert(m.lower_bound(6) == m.begin() + 4); + assert(m.lower_bound(7) == m.begin() + 4); + assert(std::as_const(m).lower_bound(8) == m.begin() + 4); + assert(std::as_const(m).lower_bound(9) == m.end()); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.end()); + assert(m.lower_bound(1) == m.begin() + 4); + assert(m.lower_bound(2) == m.begin() + 3); + assert(m.lower_bound(3) == m.begin() + 3); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 1); + assert(m.lower_bound(6) == m.begin() + 1); + assert(m.lower_bound(7) == m.begin() + 1); + assert(std::as_const(m).lower_bound(8) == m.begin()); + assert(std::as_const(m).lower_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp new file mode 100644 index 000000000000000..18f9bc6dd329553 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator lower_bound(const K& x); +// template const_iterator lower_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanLowerBound = requires(M m, Transparent k) { m.lower_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanLowerBound); +static_assert(CanLowerBound); +static_assert(!CanLowerBound); +static_assert(!CanLowerBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_lower_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.lower_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_lower_bound(m, "abc", 0); + test_lower_bound(m, "alpha", 0); + test_lower_bound(m, "beta", 1); + test_lower_bound(m, "bets", 2); + test_lower_bound(m, "charlie", 2); + test_lower_bound(m, "echo", 2); + test_lower_bound(m, "epsilon", 2); + test_lower_bound(m, "eta", 3); + test_lower_bound(m, "gamma", 4); + test_lower_bound(m, "golf", 5); + test_lower_bound(m, "zzz", 5); + + test_lower_bound(cm, "abc", 0); + test_lower_bound(cm, "alpha", 0); + test_lower_bound(cm, "beta", 1); + test_lower_bound(cm, "bets", 2); + test_lower_bound(cm, "charlie", 2); + test_lower_bound(cm, "echo", 2); + test_lower_bound(cm, "epsilon", 2); + test_lower_bound(cm, "eta", 3); + test_lower_bound(cm, "gamma", 4); + test_lower_bound(cm, "golf", 5); + test_lower_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.lower_bound(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp new file mode 100644 index 000000000000000..ab34de851031756 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator upper_bound(const key_type& k); +// const_iterator upper_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.begin()); + assert(m.upper_bound(1) == m.begin() + 1); + assert(m.upper_bound(2) == m.begin() + 2); + assert(m.upper_bound(3) == m.begin() + 2); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 4); + assert(m.upper_bound(6) == m.begin() + 4); + assert(std::as_const(m).upper_bound(7) == m.begin() + 4); + assert(std::as_const(m).upper_bound(8) == m.end()); + assert(std::as_const(m).upper_bound(9) == m.end()); + } + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.end()); + assert(m.upper_bound(1) == m.end()); + assert(m.upper_bound(2) == m.begin() + 4); + assert(m.upper_bound(3) == m.begin() + 3); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 2); + assert(m.upper_bound(6) == m.begin() + 1); + assert(m.upper_bound(7) == m.begin() + 1); + assert(std::as_const(m).upper_bound(8) == m.begin() + 1); + assert(std::as_const(m).upper_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp new file mode 100644 index 000000000000000..69ce2ae926a305e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator upper_bound(const K& x); +// template const_iterator upper_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanUpperBound = requires(M m, Transparent k) { m.upper_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanUpperBound); +static_assert(CanUpperBound); +static_assert(!CanUpperBound); +static_assert(!CanUpperBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_upper_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.upper_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_upper_bound(m, "abc", 0); + test_upper_bound(m, "alpha", 1); + test_upper_bound(m, "beta", 2); + test_upper_bound(m, "bets", 2); + test_upper_bound(m, "charlie", 2); + test_upper_bound(m, "echo", 2); + test_upper_bound(m, "epsilon", 3); + test_upper_bound(m, "eta", 4); + test_upper_bound(m, "gamma", 5); + test_upper_bound(m, "golf", 5); + test_upper_bound(m, "zzz", 5); + + test_upper_bound(cm, "abc", 0); + test_upper_bound(cm, "alpha", 1); + test_upper_bound(cm, "beta", 2); + test_upper_bound(cm, "bets", 2); + test_upper_bound(cm, "charlie", 2); + test_upper_bound(cm, "echo", 2); + test_upper_bound(cm, "epsilon", 3); + test_upper_bound(cm, "eta", 4); + test_upper_bound(cm, "gamma", 5); + test_upper_bound(cm, "golf", 5); + test_upper_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.upper_bound(Transparent{2}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h new file mode 100644 index 000000000000000..9fff262d84234e9 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -0,0 +1,294 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_flat_set_HELPERS_H +#define SUPPORT_flat_set_HELPERS_H + +#include +#include +#include +#include +#include + +#include "test_allocator.h" +#include "test_macros.h" + +template +void check_invariant(const std::flat_set& m) { + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); + auto key_equal = [&](const auto& x, const auto& y) { + const auto& c = m.key_comp(); + return !c(x, y) && !c(y, x); + }; + assert(std::adjacent_find(m.begin(), m.end(), key_equal) == m.end()); +} + +struct StartsWith { + explicit StartsWith(char ch) : lower_(1, ch), upper_(1, ch + 1) {} + StartsWith(const StartsWith&) = delete; + void operator=(const StartsWith&) = delete; + struct Less { + using is_transparent = void; + bool operator()(const std::string& a, const std::string& b) const { return a < b; } + bool operator()(const StartsWith& a, const std::string& b) const { return a.upper_ <= b; } + bool operator()(const std::string& a, const StartsWith& b) const { return a < b.lower_; } + bool operator()(const StartsWith&, const StartsWith&) const { + assert(false); // should not be called + return false; + } + }; + +private: + std::string lower_; + std::string upper_; +}; + +template +struct CopyOnlyVector : std::vector { + using std::vector::vector; + + CopyOnlyVector(const CopyOnlyVector&) = default; + CopyOnlyVector(CopyOnlyVector&& other) : CopyOnlyVector(other) {} + CopyOnlyVector(CopyOnlyVector&& other, std::vector::allocator_type alloc) : CopyOnlyVector(other, alloc) {} + + CopyOnlyVector& operator=(const CopyOnlyVector&) = default; + CopyOnlyVector& operator=(CopyOnlyVector& other) { return this->operator=(other); } +}; + +template +struct Transparent { + T t; + + operator T() const + requires ConvertibleToT + { + return t; + } +}; + +template +using ConvertibleTransparent = Transparent; + +template +using NonConvertibleTransparent = Transparent; + +struct TransparentComparator { + using is_transparent = void; + + bool* transparent_used = nullptr; + TransparentComparator() = default; + TransparentComparator(bool& used) : transparent_used(&used) {} + + template + bool operator()(const T& t, const Transparent& transparent) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return t < transparent.t; + } + + template + bool operator()(const Transparent& transparent, const T& t) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return transparent.t < t; + } + + template + bool operator()(const T& t1, const T& t2) const { + return t1 < t2; + } +}; + +struct NonTransparentComparator { + template + bool operator()(const T&, const Transparent&) const; + + template + bool operator()(const Transparent&, const T&) const; + + template + bool operator()(const T&, const T&) const; +}; + +struct NoDefaultCtr { + NoDefaultCtr() = delete; +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +struct EmplaceUnsafeContainer : std::vector { + using std::vector::vector; + + template + auto emplace(Args&&... args) -> decltype(std::declval>().emplace(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } + + template + auto insert(Args&&... args) -> decltype(std::declval>().insert(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } +}; + +template +struct ThrowOnEraseContainer : std::vector { + using std::vector::vector; + + template + auto erase(Args&&... args) -> decltype(std::declval>().erase(std::forward(args)...)) { + throw 42; + } +}; + +template +struct ThrowOnMoveContainer : std::vector { + using std::vector::vector; + + ThrowOnMoveContainer(ThrowOnMoveContainer&&) { throw 42; } + + ThrowOnMoveContainer& operator=(ThrowOnMoveContainer&&) { throw 42; } +}; + +#endif + +template +void test_emplace_exception_guarantee([[maybe_unused]] F&& emplace_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using C = TransparentComparator; + { + // Throw on emplace the key, and underlying has strong exception guarantee + using KeyContainer = std::vector>; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + + test_allocator_statistics stats; + + KeyContainer a({1, 2, 3, 4}, test_allocator{&stats}); + [[maybe_unused]] auto expected_keys = a; + M m(std::sorted_unique, std::move(a)); + + stats.throw_after = 1; + try { + emplace_function(m, 0); + assert(false); + } catch (const std::bad_alloc&) { + check_invariant(m); + // In libc++, the flat_set is unchanged + LIBCPP_ASSERT(m.size() == 4); + LIBCPP_ASSERT(std::ranges::equal(m, expected_keys)); + } + } + { + // Throw on emplace the key, and underlying has no strong exception guarantee + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(!std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + KeyContainer a = {1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + emplace_function(m, 0); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, the flat_set is cleared + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} + +template +void test_insert_range_exception_guarantee([[maybe_unused]] F&& insert_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + test_allocator_statistics stats; + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + + std::vector newValues = {0, 1, 5, 6, 7, 8}; + stats.throw_after = 1; + try { + insert_function(m, newValues); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when inserting a range + LIBCPP_ASSERT(m.size() == 0); + } +#endif +} + +template +void test_erase_exception_guarantee([[maybe_unused]] F&& erase_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + { + // key erase throws + using KeyContainer = ThrowOnEraseContainer; + using M = std::flat_set; + + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + erase_function(m, 3); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when erasing + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} +class Moveable { + int int_; + double double_; + +public: + Moveable() : int_(0), double_(0) {} + Moveable(int i, double d) : int_(i), double_(d) {} + Moveable(Moveable&& x) : int_(x.int_), double_(x.double_) { + x.int_ = -1; + x.double_ = -1; + } + Moveable& operator=(Moveable&& x) { + int_ = x.int_; + x.int_ = -1; + double_ = x.double_; + x.double_ = -1; + return *this; + } + + Moveable(const Moveable&) = delete; + Moveable& operator=(const Moveable&) = delete; + bool operator==(const Moveable& x) const { return int_ == x.int_ && double_ == x.double_; } + bool operator<(const Moveable& x) const { return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_); } + + int get() const { return int_; } + bool moved() const { return int_ == -1; } +}; + +#endif // SUPPORT_flat_set_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp new file mode 100644 index 000000000000000..c4a9810016536bd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Check that std::flat_set and its iterators can be instantiated with an incomplete +// type. + +#include +#include + +struct A { + using Set = std::flat_set; + int data; + Set m; + Set::iterator it; + Set::const_iterator cit; +}; + +// Implement the operator< required in order to instantiate flat_set +bool operator<(A const& L, A const& R) { return L.data < R.data; } + +int main(int, char**) { + A a; + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp new file mode 100644 index 000000000000000..f6d08bb736d3004 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend bool operator==(const flat_set& x, const flat_set& y); +// friend synth-three-way-result +// operator<=>(const flat_set& x, const flat_set& y); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_comparisons.h" +#include "test_container_comparisons.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, true)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } + { + // Comparisons use value_type's native operators, not the comparator + using C = std::flat_set>; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, false)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = C(std::sorted_unique, {std::numeric_limits::quiet_NaN()}); + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + } + { + // Comparisons use value_type's native operators, not the comparator + struct StrongComp { + bool operator()(double a, double b) const { return std::strong_order(a, b) < 0; } + }; + using C = std::flat_set; + C s1 = {1}; + C s2 = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + s1 = {1, std::numeric_limits::quiet_NaN(), 1}; + s2 = {std::numeric_limits::quiet_NaN(), 1}; + assert(std::lexicographical_compare_three_way(s1.begin(), s1.end(), s2.begin(), s2.end(), std::strong_order) == + std::strong_ordering::equal); + assert(s1 != s2); + assert((s1 <=> s2) == std::partial_ordering::unordered); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp new file mode 100644 index 000000000000000..a845b2b81e89d35 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// using key_type = Key; +// using value_type = Key; +// using key_compare = Compare; +// using value_compare = Compare; +// using reference = value_type&; +// using const_reference = const value_type&; +// using size_type = typename KeyContainer::size_type; +// using difference_type = typename KeyContainer::difference_type; +// using iterator = implementation-defined; // see [container.requirements] +// using const_iterator = implementation-defined; // see [container.requirements] +// using reverse_iterator = std::reverse_iterator; +// using const_reverse_iterator = std::reverse_iterator; +// using container_type = KeyContainer; + +#include +#include +#include +#include +#include +#include +#include +#include "min_allocator.h" + +void test() { + { + using M = std::flat_set; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(requires { typename M::value_compare; }); + } + + { + struct A {}; + struct Compare { + bool operator()(const std::string&, const std::string&) const; + }; + using M = std::flat_set>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + } + { + using C = std::flat_set, std::deque>>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + // size_type is invariably size_t + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>>); + } +} >From 684124e43df490e3f39d5208641a3afb93023a6a Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 13:21:24 +0000 Subject: [PATCH 2/2] review --- libcxx/include/__flat_set/flat_set.h | 137 +++---- .../flat.set/flat.set.capacity/empty.pass.cpp | 14 +- .../flat.set.capacity/max_size.pass.cpp | 8 +- .../flat.set/flat.set.capacity/size.pass.cpp | 14 +- .../flat.set/flat.set.cons/alloc.pass.cpp | 6 +- .../assign_initializer_list.pass.cpp | 19 +- .../flat.set/flat.set.cons/compare.pass.cpp | 6 +- .../flat.set.cons/containers.pass.cpp | 25 +- .../flat.set/flat.set.cons/copy.pass.cpp | 6 +- .../flat.set.cons/copy_alloc.pass.cpp | 6 +- .../copy_assign.addressof.compile.pass.cpp | 30 -- .../flat.set.cons/copy_assign.pass.cpp | 17 +- .../flat.set/flat.set.cons/deduct.pass.cpp | 353 +++++++++--------- .../flat.set/flat.set.cons/default.pass.cpp | 36 +- .../flat.set.cons/default_noexcept.pass.cpp | 58 --- .../flat.set.cons/dtor_noexcept.pass.cpp | 6 +- .../flat.set.cons/initializer_list.pass.cpp | 6 +- .../flat.set/flat.set.cons/iter_iter.pass.cpp | 6 +- .../flat.set/flat.set.cons/move.pass.cpp | 107 +++++- .../flat.set.cons/move_alloc.pass.cpp | 10 +- .../flat.set.cons/move_assign.pass.cpp | 141 ++++++- .../flat.set.cons/move_assign_clears.pass.cpp | 101 ----- .../move_assign_noexcept.pass.cpp | 85 ----- .../flat.set.cons/move_exceptions.pass.cpp | 58 --- .../flat.set.cons/move_noexcept.pass.cpp | 94 ----- .../flat.set/flat.set.cons/pmr.pass.cpp | 6 +- .../flat.set/flat.set.cons/range.pass.cpp | 6 +- .../flat.set.cons/sorted_container.pass.cpp | 6 +- .../sorted_initializer_list.pass.cpp | 10 +- .../flat.set.cons/sorted_iter_iter.pass.cpp | 6 +- .../flat.set.erasure/erase_if.pass.cpp | 20 +- .../erase_if_exceptions.pass.cpp | 7 +- .../flat.set.iterators/iterator.pass.cpp | 18 +- .../iterator_comparison.pass.cpp | 14 +- .../reverse_iterator.pass.cpp | 8 +- .../flat.set.modifiers/clear.pass.cpp | 18 +- .../flat.set.modifiers/emplace.pass.cpp | 25 +- .../flat.set.modifiers/emplace_hint.pass.cpp | 25 +- .../flat.set.modifiers/erase_iter.pass.cpp | 25 +- .../erase_iter_iter.pass.cpp | 24 +- .../flat.set.modifiers/erase_key.pass.cpp | 37 +- .../erase_key_transparent.pass.cpp | 34 +- .../flat.set.modifiers/extract.pass.cpp | 21 +- .../flat.set.modifiers/insert_cv.pass.cpp | 33 +- .../insert_initializer_list.pass.cpp | 42 ++- .../insert_iter_cv.pass.cpp | 23 +- .../insert_iter_iter.pass.cpp | 27 +- .../insert_iter_rv.pass.cpp | 43 ++- .../flat.set.modifiers/insert_range.pass.cpp | 38 +- .../flat.set.modifiers/insert_rv.pass.cpp | 42 ++- .../insert_sorted_initializer_list.pass.cpp | 35 +- .../insert_sorted_iter_iter.pass.cpp | 29 +- .../insert_transparent.pass.cpp | 21 +- .../flat.set.modifiers/replace.pass.cpp | 50 +-- .../flat.set.modifiers/swap_free.pass.cpp | 16 +- .../flat.set.modifiers/swap_member.pass.cpp | 14 +- .../flat.set/flat.set.observers/comp.pass.cpp | 6 +- .../flat.set.operations/contains.pass.cpp | 14 +- .../contains_transparent.pass.cpp | 17 +- .../flat.set.operations/count.pass.cpp | 14 +- .../count_transparent.pass.cpp | 16 +- .../flat.set.operations/equal_range.pass.cpp | 14 +- .../equal_range_transparent.pass.cpp | 16 +- .../flat.set.operations/find.pass.cpp | 14 +- .../find_transparent.pass.cpp | 16 +- .../flat.set.operations/lower_bound.pass.cpp | 14 +- .../lower_bound_transparent.pass.cpp | 16 +- .../flat.set.operations/upper_bound.pass.cpp | 14 +- .../upper_bound_transparent.pass.cpp | 17 +- .../container.adaptors/flat.set/helpers.h | 19 +- .../flat.set/incomplete_type.pass.cpp | 5 +- .../flat.set/op_compare.pass.cpp | 17 +- 72 files changed, 1214 insertions(+), 1087 deletions(-) delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index c920632c453bf5e..37e4c9f7c686b00 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP___FLAT_set_FLAT_SET_H -#define _LIBCPP___FLAT_set_FLAT_SET_H +#ifndef _LIBCPP___FLAT_SET_FLAT_SET_H +#define _LIBCPP___FLAT_SET_FLAT_SET_H #include <__algorithm/lexicographical_compare_three_way.h> #include <__algorithm/min.h> @@ -99,13 +99,6 @@ class flat_set { using const_reverse_iterator = std::reverse_iterator; using container_type = _KeyContainer; -private: - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = - uses_allocator::value; - - _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; - public: // [flat.set.cons], construct/copy/destroy _LIBCPP_HIDE_FROM_ABI @@ -178,31 +171,31 @@ class flat_set { : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( @@ -210,7 +203,7 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { @@ -219,12 +212,12 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) # if _LIBCPP_HAS_EXCEPTIONS try @@ -239,14 +232,14 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert(__first, __last); } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { @@ -254,7 +247,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { @@ -262,7 +255,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, @@ -274,37 +267,37 @@ class flat_set { } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert_range(std::forward<_Range>(__rg)); } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { insert_range(std::forward<_Range>(__rg)); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} @@ -334,11 +327,8 @@ class flat_set { // iterators _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } @@ -382,7 +372,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { return emplace(std::forward<_Kp>(__x)); } @@ -395,7 +385,7 @@ class flat_set { } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { return emplace_hint(__hint, std::forward<_Kp>(__x)); } @@ -425,7 +415,7 @@ class flat_set { __reserve(ranges::size(__range)); } - __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + __append_sort_merge_unique(std::forward<_Range>(__range)); } _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } @@ -468,7 +458,7 @@ class flat_set { } template - requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> && !is_convertible_v<_Kp &&, const_iterator>) _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { auto [__first, __last] = equal_range(__x); @@ -505,13 +495,13 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { return __find_impl(*this, __x); } @@ -519,7 +509,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { return contains(__x) ? 1 : 0; } @@ -527,7 +517,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { return find(__x) != end(); } @@ -541,13 +531,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { return ranges::lower_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { return ranges::lower_bound(__keys_, __x, __compare_); } @@ -561,13 +551,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { return ranges::upper_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { return ranges::upper_bound(__keys_, __x, __compare_); } @@ -581,12 +571,12 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { return __equal_range_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { return __equal_range_impl(*this, __x); } @@ -611,14 +601,14 @@ class flat_set { }; template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), __compare_(std::forward<_CompArg>(__comp)...) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc)), __compare_(std::forward<_CompArg>(__comp)...) {} @@ -637,17 +627,30 @@ class flat_set { __keys_.erase(__dup_start, __keys_.end()); } - template - _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { - auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); - size_type __old_size = size(); - if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { - __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + template + _LIBCPP_HIDE_FROM_ABI void __append(_InputIterator __first, _InputIterator __last) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append(_Range&& __rng) { + if constexpr (requires { __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); }) { + // C++23 Sequence Container should have insert_range member function + __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); + } else if constexpr (ranges::common_range<_Range>) { + __keys_.insert(__keys_.end(), ranges::begin(__rng), ranges::end(__rng)); } else { - for (; __first != __last; ++__first) { - __keys_.insert(__keys_.end(), *__first); + for (auto&& __x : __rng) { + __keys_.insert(__keys_.end(), std::forward(__x)); } } + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_Args&&... __args) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + __append(std::forward<_Args>(__args)...); if (size() != __old_size) { if constexpr (!_WasSorted) { ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); @@ -831,18 +834,18 @@ template struct uses_allocator, _Allocator> : bool_constant> {}; - template - _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type - erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { - auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); - auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { - return static_cast(__pred(e)); - }); - auto __res = __flat_set.__keys_.end() - __it; - __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); - __guard.__complete(); - return __res; - } +template +_LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type +erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; +} _LIBCPP_END_NAMESPACE_STD @@ -850,4 +853,4 @@ _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS -#endif // _LIBCPP___FLAT_set_FLAT_SET_H +#endif // _LIBCPP___FLAT_SET_FLAT_SET_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp index 204df1d681af1bc..223b92fc3e8e84f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m; @@ -38,11 +38,15 @@ void test() { assert(m.empty()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index cd7f424e00ece23..0489d8862579119 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -24,7 +24,8 @@ #include "test_allocator.h" #include "test_macros.h" -int main(int, char**) { +void test() { + { using A1 = limited_allocator; using C = std::flat_set, std::vector>; @@ -59,5 +60,10 @@ int main(int, char**) { assert(c.max_size() <= max_dist); assert(c.max_size() <= alloc_max_size(std::allocator())); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp index 7c156e95ecb1c86..9f5ffdd06635133 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; using S = typename M::size_type; { @@ -56,11 +56,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp index acc0817d7cac4d6..d14e883dd5e9362 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -22,7 +22,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -55,6 +55,10 @@ int main(int, char**) { auto v = std::move(m).extract(); assert(v.get_allocator().get_id() == 5); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7f75f1e1611e3b4..7e948d7c5fe976b 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -33,7 +33,6 @@ void test() { m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); - LIBCPP_ASSERT(std::ranges::equal(m, expected)); } { M m = {10, 8}; @@ -44,13 +43,17 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp index b3bee18f5a936b1..110757a1bb9ab6a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -78,6 +78,10 @@ int main(int, char**) { auto keys = std::move(m).extract(); assert(keys.get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp index 3d1e6240c952e8c..6b1246885bf5276 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -36,7 +36,7 @@ void conversion_test(T); template concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -116,21 +116,16 @@ int main(int, char**) { auto m = M(ks, A(4)); // replaces the allocators assert(!ks.empty()); // it was an lvalue above assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); + auto keys = M(m).extract(); assert(keys.get_allocator() == A(4)); - } - { - // flat_set(container_type , const Allocator&) + // explicit(false) - using A = test_allocator; - using M = std::flat_set, std::deque>; static_assert(ImplicitlyConstructible&, const A&>); - auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); - M m = {ks, A(4)}; // implicit ctor - assert(!ks.empty()); // it was an lvalue above - assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); - assert(keys.get_allocator() == A(4)); + M m2 = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert(m2 == m); + auto keys2 = std::move(m).extract(); + assert(keys2.get_allocator() == A(4)); } { // flat_set(container_type , key_compare, const Allocator&) @@ -153,6 +148,10 @@ int main(int, char**) { keys = std::move(m2).extract(); assert(keys.get_allocator() == A(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp index f1dbc955e1b0de7..1ba550d98f01f6d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -21,7 +21,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; std::vector> ks({1, 3, 5}, test_allocator(6)); @@ -59,6 +59,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == other_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp index 59fb9d0a38366fe..5011bd200306419 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -23,7 +23,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -58,6 +58,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == test_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp deleted file mode 100644 index 169b469f3bca68b..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp +++ /dev/null @@ -1,30 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(const flat_set& s); - -// Validate whether the container can be copy-assigned (move-assigned, swapped) -// with an ADL-hijacking operator& - -#include -#include - -#include "test_macros.h" -#include "operator_hijacker.h" - -void test() { - std::flat_set so; - std::flat_set s; - s = so; - s = std::move(so); - swap(s, so); -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp index cdd5045f4bb9f7e..695363e3aeababe 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -17,11 +17,12 @@ #include #include +#include "operator_hijacker.h" #include "test_macros.h" #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // test_allocator is not propagated using C = test_less; @@ -81,5 +82,19 @@ int main(int, char**) { m = static_cast(m); assert((m == M{{1, 2}})); } + { + // Validate whether the container can be copy-assigned (move-assigned, swapped) + // with an ADL-hijacking operator& + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); + } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp index 612e64a7c42f23e..607fe0d1a9713a9 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -26,24 +26,21 @@ #include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" -using P = std::pair; -using PC = std::pair; - void test_copy() { { - std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set source = {1, 2}; std::flat_set s(source); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s{source}; // braces instead of parens ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s(source, std::allocator()); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); @@ -52,275 +49,259 @@ void test_copy() { void test_containers() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); - std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + int expected[] = {1, 2, 3, INT_MAX}; { - std::flat_set s(ks, vs); + std::flat_set s(ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + std::flat_set s(std::sorted_unique, sorted_ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, test_allocator(0, 44)); + std::flat_set s(ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_containers_compare() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); - std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + int expected[] = {INT_MAX, 3, 2, 1}; { - std::flat_set s(ks, vs, std::greater()); + std::flat_set s(ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_iter_iter() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const int arr[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arr[] = {1, 2, 3, INT_MAX}; + const int arrc[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arrc[] = {1, 2, 3, INT_MAX}; { std::flat_set m(std::begin(arr), std::end(arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::begin(arrc), std::end(arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.begin(), mo.end()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.cbegin(), mo.cend()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); - } - { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); + // This does not deduce to flat_set(InputIterator, InputIterator) + // But deduces to flat_set(initializer_list) + int source[3] = {1, 2, 3}; + std::flat_set s = {source, source + 3}; + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 2); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + int source[3] = {1, 2, 3}; std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); assert(s.size() == 3); } } void test_iter_iter_compare() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m(std::begin(arr), std::end(arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::begin(arrc), std::end(arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set mo; - std::flat_set m(mo.begin(), mo.end(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } - { - std::flat_set mo; - std::flat_set m(mo.cbegin(), mo.cend(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } + // const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m(std::begin(arr), std::end(arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.begin(), mo.end(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.cbegin(), mo.cend(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } } void test_initializer_list() { - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - { - std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - } - { - using M = std::flat_set; - M m; - std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - assert(s[m] == m); - } + // const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + // { + // std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // } + // { + // using M = std::flat_set; + // M m; + // std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // assert(s[m] == m); + // } } void test_initializer_list_compare() { - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } } void test_from_range() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; - { - std::flat_set s(std::from_range, r); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + // { + // std::flat_set s(std::from_range, r); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } void test_from_range_compare() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; - { - std::flat_set s(std::from_range, r, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + // { + // std::flat_set s(std::from_range, r, std::greater()); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } int main(int, char**) { @@ -335,7 +316,7 @@ int main(int, char**) { test_from_range(); test_from_range_compare(); - AssociativeContainerDeductionGuidesSfinaeAway>(); + AssociativeContainerDeductionGuidesSfinaeAway>(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp index 64b0bfcb383a720..292af96c61582fa 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -19,9 +19,10 @@ #include #include -#include "test_macros.h" #include "min_allocator.h" +#include "MoveOnly.h" #include "test_allocator.h" +#include "test_macros.h" struct DefaultCtableComp { explicit DefaultCtableComp() { default_constructed_ = true; } @@ -29,7 +30,12 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +void test() { { std::flat_set m; assert(m.empty()); @@ -60,6 +66,32 @@ int main(int, char**) { assert(m.key_comp().default_constructed_); } } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp deleted file mode 100644 index b4a3b6de205a31b..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set() -// noexcept( -// is_nothrow_default_constructible_v && -// is_nothrow_default_constructible_v); - -// This tests a conforming extension - -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -struct ThrowingCtorComp { - ThrowingCtorComp() noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -int main(int, char**) { -#if defined(_LIBCPP_VERSION) - { - using C = std::flat_set; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set, std::vector>>; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } -#endif // _LIBCPP_VERSION - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp index c0d315c0ce74b4b..fa1e2478af45997 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -27,7 +27,7 @@ struct ThrowingDtorComp { ~ThrowingDtorComp() noexcept(false) {} }; -int main(int, char**) { +void test() { { using C = std::flat_set; static_assert(std::is_nothrow_destructible_v); @@ -52,6 +52,10 @@ int main(int, char**) { C c; } #endif // _LIBCPP_VERSION +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp index cd2319e91f760d9..9aed5c88ee72680 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -35,7 +35,7 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -146,6 +146,10 @@ int main(int, char**) { M m({5, 2, 2, 3, 1, 3}, {}, a); assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp index 65eebc21a66c4cb..2d0b07c9155fdba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -29,7 +29,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -131,6 +131,10 @@ int main(int, char**) { LIBCPP_ASSERT(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp index 69b340ad09fe158..b2853844b986c6e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -25,7 +25,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; using A = test_allocator; @@ -79,5 +79,110 @@ int main(int, char**) { LIBCPP_ASSERT(m1.empty()); LIBCPP_ASSERT(m1.size() == 0); } +} + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +void test_move_noexcept() { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +} + +#if !defined(TEST_HAS_NO_EXCEPTIONS) +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +void test_move_exception() { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } +} +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + +int main(int, char**) { + test(); + test_move_noexcept(); +#if !defined(TEST_HAS_NO_EXCEPTIONS) + test_move_exception(); +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp index fc7f68d8c967ad2..489b6ff36324b3f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -53,7 +53,7 @@ int main(int, char**) { assert(m.size() == 3); auto keys = std::move(m).extract(); assert(keys.get_allocator() == A(3)); - assert(std::ranges::equal(keys, expected )); + assert(std::ranges::equal(keys, expected)); // The original flat_set is moved-from. assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); @@ -63,13 +63,17 @@ int main(int, char**) { } { // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, CopyOnlyVector>; + using M = std::flat_set, CopyOnlyVector>; M m1 = M({1, 2, 3}); M m2(std::move(m1), std::allocator{}); assert(m2.size() == 3); check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index b16dc38dd402859..e55a0516ed1bed2 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -22,11 +22,144 @@ #include "test_macros.h" #include "MoveOnly.h" +#include "../helpers.h" #include "../../../test_compare.h" #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +void test_move_assign_clears() { + // Preserves the class invariant for the moved-from flat_set. + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } +} + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +void test_move_assign_no_except() { + // This tests a conforming extension + + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } +} + +void test() { { using C = test_less; using A1 = test_allocator; @@ -64,6 +197,12 @@ int main(int, char**) { assert(ks.get_allocator() == A()); assert(mo.empty()); } +} + +int main(int, char**) { + test(); + test_move_assign_clears(); + test_move_assign_no_except(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp deleted file mode 100644 index 50817f4be8a8125..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&&); -// Preserves the class invariant for the moved-from flat_set. - -#include -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -struct MoveNegates { - int value_ = 0; - MoveNegates() = default; - MoveNegates(int v) : value_(v) {} - MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } - MoveNegates& operator=(MoveNegates&& rhs) { - value_ = rhs.value_; - rhs.value_ = -rhs.value_; - return *this; - } - ~MoveNegates() = default; - auto operator<=>(const MoveNegates&) const = default; -}; - -struct MoveClears { - int value_ = 0; - MoveClears() = default; - MoveClears(int v) : value_(v) {} - MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } - MoveClears& operator=(MoveClears&& rhs) { - value_ = rhs.value_; - rhs.value_ = 0; - return *this; - } - ~MoveClears() = default; - auto operator<=>(const MoveClears&) const = default; -}; - -int main(int, char**) { - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, std::vector>; - M m1 = M({1, 2, 3}); - M m2 = M({1, 2}); - m2 = std::move(m1); - assert(m2.size() == 3); - check_invariant(m1); - LIBCPP_ASSERT(m1.empty()); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp deleted file mode 100644 index 86f3568f0d67a6b..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&& c) -// noexcept( -// is_nothrow_move_assignable::value && -// is_nothrow_move_assignable::value && -// is_nothrow_copy_assignable::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include - -#include "MoveOnly.h" -#include "test_allocator.h" -#include "test_macros.h" - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -struct MoveThrowsComp { - MoveThrowsComp(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp(const MoveThrowsComp&) noexcept(true); - MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); - bool operator()(const auto&, const auto&) const; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - // Test with a comparator that throws on move-assignment. - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); - } - { - // Test with a container that throws on move-assignment. - using C = std::flat_set, std::pmr::vector>; - static_assert(!std::is_nothrow_move_assignable_v); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp deleted file mode 100644 index 17e4e40387606ce..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 -// UNSUPPORTED: no-exceptions - -// - -// flat_set(flat_set&& s); -// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. - -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -static int countdown = 0; - -struct EvilContainer : std::vector { - EvilContainer() = default; - EvilContainer(EvilContainer&& rhs) { - // Throw on move-construction. - if (--countdown == 0) { - rhs.insert(rhs.end(), 0); - rhs.insert(rhs.end(), 0); - throw 42; - } - } -}; - -int main(int, char**) { - { - using M = std::flat_set, EvilContainer>; - M mo = {1, 2, 3}; - countdown = 1; - try { - M m = std::move(mo); - assert(false); // not reached - } catch (int x) { - assert(x == 42); - } - // The source flat_set maintains its class invariant. - check_invariant(mo); - LIBCPP_ASSERT(mo.empty()); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp deleted file mode 100644 index 49d1151fd8a993c..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set(flat_set&&) -// noexcept(is_nothrow_move_constructible::value && -// is_nothrow_move_constructible::value && -// is_nothrow_copy_constructible::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -template -struct ThrowingMoveAllocator { - using value_type = T; - explicit ThrowingMoveAllocator() = default; - ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; - ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} - T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } - void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } - friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; -}; - -struct ThrowingMoveComp { - ThrowingMoveComp() = default; - ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} - ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - { - using C = std::flat_set, std::deque>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#if _LIBCPP_VERSION - { - // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators - using C = std::flat_set, std::deque>>; - static_assert(!std::is_nothrow_move_constructible_v>>); - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#endif // _LIBCPP_VERSION - { - // Comparator fails to be nothrow-move-constructible - using C = std::flat_set; - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp index 785718d2eed333f..1a4eafa8802918d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -28,7 +28,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // flat_set(const Allocator& a); using M = std::flat_set, std::pmr::vector>; @@ -317,6 +317,10 @@ int main(int, char**) { assert(vm[0].key_comp() == C(4)); assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp index bb9f99c228bfecc..bd7b5c12432e962 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -56,7 +56,7 @@ static_assert( !std:: is_constructible_v>, std::less, std::allocator>); -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -168,6 +168,10 @@ int main(int, char**) { assert(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp index 2d442d49667bd07..873ff32b62936a5 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -138,6 +138,10 @@ int main(int, char**) { assert(m2 == m); assert(std::move(m2).extract().get_allocator() == A(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp index 01956a78c7f48dd..a8dac35aefee81f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -33,10 +33,10 @@ template std::initializer_list il = {1, 2, 4, 5}; -const auto il1 = il; -const auto il2 = il; +void test() { + const auto il1 = il; + const auto il2 = il; -int main(int, char**) { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -145,6 +145,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp index b5229a84dd51333..b184ee9c3f5abae 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -28,7 +28,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -151,6 +151,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp index 134db83aef3cad2..806779bc7d16bc1 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -49,7 +49,7 @@ void test0( } template -void test() { +void test_one() { // Test all the plausible signatures for this predicate. auto is1 = [](typename S::const_reference v) { return v == 1; }; auto is2 = [](typename S::value_type v) { return v == 2; }; @@ -76,14 +76,18 @@ void test() { test0({1, 2, 3}, False, {1, 2, 3}, 0); } +void test() { + test_one>(); + test_one, std::vector>>>(); + test_one, std::vector>>>(); + test_one, std::deque>>>(); + test_one, std::deque>>>(); + test_one>(); + test_one>(); +} + int main(int, char**) { - test>(); - test, std::vector>>>(); - test, std::vector>>>(); - test, std::deque>>>(); - test, std::deque>>>(); - test>(); - test>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp index 6bbe1ad4f016705..37b4a40f0165cfe 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -65,7 +65,7 @@ struct ErasurePredicate { bool operator()(const auto& x) const { return (3 <= x && x <= 5); } }; -int main(int, char**) { +void test() { const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; { using M = std::flat_set; @@ -124,5 +124,10 @@ int main(int, char**) { } } } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp index c07297a141ad109..846bcff63d77365 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -30,7 +30,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -67,15 +67,15 @@ void test() { assert(i == m.begin()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::iterator ii1{}, ii2{}; C::iterator ii4 = ii1; C::const_iterator cii{}; @@ -88,6 +88,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp index 29441dcc57d40e4..3027cdd4076eea4 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using KI = typename KeyContainer::iterator; @@ -144,11 +144,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp index a16383cdcf53830..d1e4cef3de19e83 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include -int main(int, char**) { +void test() { { using M = std::flat_set, std::deque>; M m = {1, 2, 3, 4}; @@ -69,7 +69,7 @@ int main(int, char**) { } { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::reverse_iterator ii1{}, ii2{}; C::reverse_iterator ii4 = ii1; C::const_reverse_iterator cii{}; @@ -82,6 +82,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp index 221a13fa057577a..efa13a51c30bb35 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -38,7 +38,7 @@ static_assert(NoExceptClear, ThrowOnMoveContai #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -50,13 +50,17 @@ void test() { assert(m.size() == 0); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp index 95f7a3c5f5d34a2..79800e894afbfc9 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -28,7 +28,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -121,21 +121,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp index de855d5e5c30097..b3bd8adf0c35d8a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -27,7 +27,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = M::iterator; @@ -134,21 +134,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp index 386af04d26e9a2e..42562b84b4e22d7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -27,7 +27,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -106,16 +106,21 @@ void test() { assert(i8 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp index 7416977844e5df2..d402a7ba0285ec8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -77,15 +77,21 @@ void test() { assert(i4 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp index 25d4f4af19608b4..d81422d38718761 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template > -void test() { +void test_one() { using M = std::flat_set; auto make = [](std::initializer_list il) { @@ -70,22 +70,27 @@ void test() { assert(m.empty()); } -int main(int, char**) { - test>(); - test, std::greater<>>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one, std::greater<>>(); + test_one>(); + test_one>(); + test_one>>(); +} - { - auto erase_function = [](auto& m, auto key_arg) { - using Map = std::decay_t; - using Key = typename Map::key_type; - const Key key{key_arg}; - m.erase(key); - }; - test_erase_exception_guarantee(erase_function); - } +void test_exception() { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp index cbf7cac603806d7..c383844eb4973ec 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -50,7 +50,7 @@ struct HeterogeneousKey { }; template -void test_simple() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -86,11 +86,11 @@ void test_transparent_comparator() { assert(m == expected); } -int main(int, char**) { - test_simple>(); - test_simple>(); - test_simple>(); - test_simple>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_transparent_comparator>(); test_transparent_comparator>(); @@ -129,14 +129,20 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } - { - auto erase_transparent = [](auto& m, auto key_arg) { - using Set = std::decay_t; - using Key = typename Set::key_type; - m.erase(Transparent{key_arg}); - }; - test_erase_exception_guarantee(erase_transparent); - } +} + +void test_exception() { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp index c3bbffabb90a08f..dfa21a807f0254e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -33,7 +33,7 @@ static_assert(!CanExtract const&>); static_assert(!CanExtract const&&>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; M m = M({1, 2, 3}); @@ -45,11 +45,12 @@ void test() { LIBCPP_ASSERT(m.empty()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { // extracted object maintains invariant if the underlying container does not clear after move using M = std::flat_set, CopyOnlyVector>; @@ -59,7 +60,9 @@ int main(int, char**) { check_invariant(m); LIBCPP_ASSERT(m.empty()); } +} +void test_exception() { { #ifndef TEST_HAS_NO_EXCEPTIONS using KeyContainer = ThrowOnMoveContainer; @@ -79,5 +82,11 @@ int main(int, char**) { } #endif } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp index c0ddadc30069872..e0cb80f74462cd0 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -59,20 +59,25 @@ void test() { assert(*r.first == 3); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using value_type = typename std::decay_t::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(p); - }; - test_emplace_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp index 7381514a70eabbb..bf94fd9f5b11fda 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -23,12 +23,12 @@ #include "min_allocator.h" template -void test() { - using Key = typename KeyContainer::value_type; - using M = std::flat_set, KeyContainer>; - using V = typename M::value_type; +void test_one() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; - M m = {1,1,1,3,3,3}; + M m = {1, 1, 1, 3, 3, 3}; m.insert({ 4, 4, @@ -48,20 +48,26 @@ void test() { assert(*std::next(m.begin(), 3) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(il); - }; - test_insert_range_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index c343d53a62215a8..d6791853e0debdb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = typename M::iterator; @@ -55,13 +55,15 @@ void test() { assert(*r == 3); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; using value_type = typename FlatSet::value_type; @@ -69,6 +71,11 @@ int main(int, char**) { m.insert(m.begin(), p); }; test_emplace_exception_guarantee(insert_func); - } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp index d20a8ef8fdd92d8..8063686c960ed3f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; int ar1[] = { @@ -73,15 +73,22 @@ void test() { M expected2{0, 1, 2, 3, 4}; assert(m == expected2); } + +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp index 84b6c7fc1d34f62..d29de98e4d3ddbf 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -22,7 +22,7 @@ #include "test_macros.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -49,25 +49,30 @@ void test() { assert(*r == V(3)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(m.begin(), std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp index 536307252c64058..ed33827a7355c94 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -39,7 +39,7 @@ static_assert(!CanInsertRange*>>) static_assert(!CanInsertRange*>>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -75,31 +75,29 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { - // Items are forwarded correctly from the input range (P2767). + // Items are forwarded correctly from the input range. MoveOnly a[] = {3, 1, 4, 1, 5}; std::flat_set m; m.insert_range(a | std::views::as_rvalue); MoveOnly expected[] = {1, 3, 4, 5}; assert(std::ranges::equal(m, expected)); } - { - // The element type of the range doesn't need to be std::pair (P2767). - int pa[] = {3, 1, 4, 1, 5}; - std::deque> a(pa, pa + 5); - std::flat_set m; - m.insert_range(a); - int expected[] = {1, 3, 4, 5}; - assert(std::ranges::equal(m, expected)); - } - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; - test_insert_range_exception_guarantee(insert_func); - } +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp index 7d95f0521eb1f67..faf74142caff5c0 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -25,7 +25,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; using R = std::pair; @@ -57,24 +57,30 @@ void test() { assert(*r.first == V(3)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp index fa5bf86830daecd..38c36d1befaa7c4 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -38,21 +38,26 @@ void test() { assert(*std::next(m.begin(), 4) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(std::sorted_unique, il); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp index ef7b8391cee33c1..6258c4dbfdcbba3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -60,18 +60,23 @@ void test() { assert(m == expected2); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - m.insert(std::sorted_unique, newValues.begin(), newValues.end()); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp index 72d7261a1825477..d2ddf95aac2bb78 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -57,7 +57,7 @@ struct CompareCounter { }; template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -121,11 +121,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // no ambiguity between insert(pos, P&&) and insert(first, last) @@ -139,6 +139,9 @@ int main(int, char**) { ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); } +} + +void test_exception() { { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; @@ -165,5 +168,11 @@ int main(int, char**) { }; test_emplace_exception_guarantee(insert_func_iter); } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp index 49cb6eb6163c903..fca33bd41449e08 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -31,7 +31,7 @@ static_assert(CanReplace>); static_assert(!CanReplace&>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -43,30 +43,36 @@ void test() { assert(std::ranges::equal(m, expected_keys)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { #ifndef TEST_HAS_NO_EXCEPTIONS - using KeyContainer = ThrowOnMoveContainer; - using M = std::flat_set; + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; - M m; - m.emplace(1); - m.emplace(2); - try { - KeyContainer new_keys{3, 4}; - m.replace(std::move(new_keys)); - assert(false); - } catch (int) { - check_invariant(m); - // In libc++, we clear the map - LIBCPP_ASSERT(m.size() == 0); - } -#endif + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); } +#endif +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp index bc7baa67e52a599..ed13ba1ef3fea71 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -24,6 +24,8 @@ #include "test_macros.h" #include "../helpers.h" +#include "check_assertion.h" + // test noexcept template @@ -38,7 +40,7 @@ static_assert(NoExceptAdlSwap, ThrowOnMoveCont #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -84,11 +86,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp index b0b06a9499efc7a..1eac55d768ce0bc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -37,7 +37,7 @@ static_assert(NoExceptMemberSwap, ThrowOnMoveC #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -82,11 +82,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp index 971b5e1c338dd11..ba2c428c9e30e2b 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -21,7 +21,7 @@ #include "test_macros.h" -int main(int, char**) { +void test() { { using M = std::flat_set; using Comp = std::less; // the default @@ -67,6 +67,10 @@ int main(int, char**) { assert(vc(1, 2)); assert(!vc(2, 1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp index b14da66f611301e..e23683f6f289457 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp index 507560608952b01..0cdff44d11274fd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanContains); static_assert(!CanContains); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.contains(Transparent{"g"}) == false); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,5 +66,10 @@ int main(int, char**) { assert(b); assert(transparent_used); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp index 478f615358b6068..017f0fed3e9816d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using S = typename KeyContainer::size_type; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp index b591258f74399c8..0c5ce9d5799651a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanCount); static_assert(!CanCount); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.count(Transparent{"g"}) == 0); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,6 +66,10 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp index a088b7fee17d2ca..b55cbe2ac42a001 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -67,11 +67,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp index ede5d91e19b9fdd..97c4af19eaef377 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanEqualRange); static_assert(!CanEqualRange); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -77,11 +77,11 @@ void test() { test_not_found(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -92,6 +92,10 @@ int main(int, char**) { assert(p.first != p.second); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp index cf0dd2d1dd831c8..9ee8f043e1d9cdd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -25,7 +25,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m = {1, 2, 4, 5, 8}; @@ -43,11 +43,15 @@ void test() { assert(std::as_const(m).find(9) == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp index 730a57b0a6cb855..cc8ea12bcf4a6a3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanFind); static_assert(!CanFind); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -68,11 +68,11 @@ void test() { test_find(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -83,6 +83,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp index 093c32e537ed35f..1ceddb2f1c9d26e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -60,11 +60,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp index 18f9bc6dd329553..19991ca05fbc8a9 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanLowerBound); static_assert(!CanLowerBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,11 @@ void test() { test_lower_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -89,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp index ab34de851031756..f25896e12293977 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -61,11 +61,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp index 69ce2ae926a305e..c9b519d20321933 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanUpperBound); static_assert(!CanUpperBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,12 @@ void test() { test_upper_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { bool transparent_used = false; TransparentComparator c(transparent_used); @@ -88,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h index 9fff262d84234e9..2ee8b021337a06a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SUPPORT_flat_set_HELPERS_H -#define SUPPORT_flat_set_HELPERS_H +#ifndef SUPPORT_FLAT_SET_HELPERS_H +#define SUPPORT_FLAT_SET_HELPERS_H #include #include @@ -149,6 +149,19 @@ struct EmplaceUnsafeContainer : std::vector { throw 42; } + + template + auto insert_range(Args&&... args) + -> decltype(std::declval>().insert_range(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } }; template @@ -291,4 +304,4 @@ class Moveable { bool moved() const { return int_ == -1; } }; -#endif // SUPPORT_flat_set_HELPERS_H +#endif // SUPPORT_FLAT_SET_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp index c4a9810016536bd..faf746861df309f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -27,7 +27,10 @@ struct A { // Implement the operator< required in order to instantiate flat_set bool operator<(A const& L, A const& R) { return L.data < R.data; } +void test() { A a; } + int main(int, char**) { - A a; + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp index f6d08bb736d3004..3e7aecee77fdd88 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -31,7 +31,7 @@ #include "test_container_comparisons.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -69,11 +69,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { using C = std::flat_set; @@ -101,5 +101,10 @@ int main(int, char**) { assert(s1 != s2); assert((s1 <=> s2) == std::partial_ordering::unordered); } +} + +int main(int, char**) { + test(); + return 0; } From libcxx-commits at lists.llvm.org Sun Feb 2 05:39:49 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Sun, 02 Feb 2025 05:39:49 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][format] Discard contents since null-terminator in character arrays in formatting (PR #116571) In-Reply-To: Message-ID: <679f75a5.050a0220.1b0c39.346a@mx.google.com> https://github.com/mordante edited https://github.com/llvm/llvm-project/pull/116571 From libcxx-commits at lists.llvm.org Sun Feb 2 05:39:50 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Sun, 02 Feb 2025 05:39:50 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][format] Discard contents since null-terminator in character arrays in formatting (PR #116571) In-Reply-To: Message-ID: <679f75a6.170a0220.aa435.0e7c@mx.google.com> https://github.com/mordante commented: Thanks for working on this. A few comments. https://github.com/llvm/llvm-project/pull/116571 From libcxx-commits at lists.llvm.org Sun Feb 2 05:39:50 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Sun, 02 Feb 2025 05:39:50 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][format] Discard contents since null-terminator in character arrays in formatting (PR #116571) In-Reply-To: Message-ID: <679f75a6.170a0220.3111d9.17aa@mx.google.com> ================ @@ -3189,6 +3189,12 @@ void format_tests(TestFunction check, ExceptionTest check_exception) { const CharT* data = buffer; check(SV("hello 09azAZ!"), SV("hello {}"), data); } + { + // https://github.com/llvm/llvm-project/issues/115935 + // Contents after the embedded null character are discarded. + CharT buffer[] = {CharT('a'), CharT('b'), CharT('c'), 0, CharT('d'), CharT('e'), CharT('f'), 0}; ---------------- mordante wrote: Can you add a second test case using `CharT buffer[] = {CharT('a'), CharT('b'), CharT('c'), 0, CharT('d'), CharT('e'), CharT('f')};` (so without the final NUL character.) https://github.com/llvm/llvm-project/pull/116571 From libcxx-commits at lists.llvm.org Sun Feb 2 05:39:50 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Sun, 02 Feb 2025 05:39:50 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][format] Discard contents since null-terminator in character arrays in formatting (PR #116571) In-Reply-To: Message-ID: <679f75a6.050a0220.118a7d.0eab@mx.google.com> ================ @@ -32,6 +33,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace __format { +template +inline constexpr bool __is_bounded_array_of = false; + +template +inline constexpr bool __is_bounded_array_of<_Elem[_Len], _Elem> = true; + ---------------- mordante wrote: Are these really useful? They are only used twice. https://github.com/llvm/llvm-project/pull/116571 From libcxx-commits at lists.llvm.org Sun Feb 2 06:08:17 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Sun, 02 Feb 2025 06:08:17 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] implement std::flat_set (PR #125241) In-Reply-To: Message-ID: <679f7c51.170a0220.b11a7.6088@mx.google.com> https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/125241 >From a0f80fcd8c55154c89535488479872de34e5c8dd Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Fri, 31 Jan 2025 15:53:09 +0000 Subject: [PATCH 1/3] [libc++] implement std::flat_set --- libcxx/include/CMakeLists.txt | 2 + libcxx/include/__flat_set/flat_set.h | 853 ++++++++++++++++++ libcxx/include/flat_set | 59 ++ libcxx/include/module.modulemap | 11 + .../flat.set/flat.set.capacity/empty.pass.cpp | 48 + .../flat.set.capacity/empty.verify.cpp | 20 + .../flat.set.capacity/max_size.pass.cpp | 63 ++ .../flat.set/flat.set.capacity/size.pass.cpp | 66 ++ .../flat.set/flat.set.cons/alloc.pass.cpp | 60 ++ .../assign_initializer_list.pass.cpp | 56 ++ .../flat.set/flat.set.cons/compare.pass.cpp | 83 ++ .../flat.set.cons/containers.pass.cpp | 158 ++++ .../flat.set/flat.set.cons/copy.pass.cpp | 64 ++ .../flat.set.cons/copy_alloc.pass.cpp | 63 ++ .../copy_assign.addressof.compile.pass.cpp | 30 + .../flat.set.cons/copy_assign.pass.cpp | 85 ++ .../flat.set.cons/deduct.compile.pass.cpp | 49 + .../flat.set/flat.set.cons/deduct.pass.cpp | 341 +++++++ .../flat.set.cons/deduct_pmr.pass.cpp | 94 ++ .../flat.set/flat.set.cons/default.pass.cpp | 65 ++ .../flat.set.cons/default_noexcept.pass.cpp | 58 ++ .../flat.set.cons/dtor_noexcept.pass.cpp | 57 ++ .../flat.set.cons/initializer_list.pass.cpp | 151 ++++ .../flat.set/flat.set.cons/iter_iter.pass.cpp | 136 +++ .../flat.set/flat.set.cons/move.pass.cpp | 83 ++ .../flat.set.cons/move_alloc.pass.cpp | 75 ++ .../flat.set.cons/move_assign.pass.cpp | 69 ++ .../flat.set.cons/move_assign_clears.pass.cpp | 101 +++ .../move_assign_noexcept.pass.cpp | 85 ++ .../flat.set.cons/move_exceptions.pass.cpp | 58 ++ .../flat.set.cons/move_noexcept.pass.cpp | 94 ++ .../flat.set/flat.set.cons/pmr.pass.cpp | 322 +++++++ .../flat.set/flat.set.cons/range.pass.cpp | 173 ++++ .../flat.set.cons/sorted_container.pass.cpp | 143 +++ .../sorted_initializer_list.pass.cpp | 150 +++ .../flat.set.cons/sorted_iter_iter.pass.cpp | 156 ++++ .../flat.set.erasure/erase_if.pass.cpp | 89 ++ .../erase_if_exceptions.pass.cpp | 128 +++ .../flat.set.iterators/iterator.pass.cpp | 93 ++ .../iterator_comparison.pass.cpp | 154 ++++ ...rator_concept_conformance.compile.pass.cpp | 77 ++ ...range_concept_conformance.compile.pass.cpp | 52 ++ .../reverse_iterator.pass.cpp | 87 ++ .../flat.set.modifiers/clear.pass.cpp | 62 ++ .../flat.set.modifiers/emplace.pass.cpp | 141 +++ .../flat.set.modifiers/emplace_hint.pass.cpp | 154 ++++ .../flat.set.modifiers/erase_iter.pass.cpp | 121 +++ .../erase_iter_iter.pass.cpp | 91 ++ .../flat.set.modifiers/erase_key.pass.cpp | 91 ++ .../erase_key_transparent.pass.cpp | 142 +++ .../flat.set.modifiers/extract.pass.cpp | 83 ++ .../flat.set.modifiers/insert_cv.pass.cpp | 78 ++ .../insert_initializer_list.pass.cpp | 67 ++ .../insert_iter_cv.pass.cpp | 74 ++ .../insert_iter_iter.pass.cpp | 87 ++ .../insert_iter_rv.pass.cpp | 73 ++ .../flat.set.modifiers/insert_range.pass.cpp | 105 +++ .../flat.set.modifiers/insert_rv.pass.cpp | 80 ++ .../insert_sorted_initializer_list.pass.cpp | 58 ++ .../insert_sorted_iter_iter.pass.cpp | 77 ++ .../insert_transparent.pass.cpp | 169 ++++ .../flat.set.modifiers/replace.pass.cpp | 72 ++ .../swap_exception.pass.cpp | 61 ++ .../flat.set.modifiers/swap_free.pass.cpp | 94 ++ .../flat.set.modifiers/swap_member.pass.cpp | 92 ++ .../flat.set/flat.set.observers/comp.pass.cpp | 72 ++ .../flat.set.operations/contains.pass.cpp | 69 ++ .../contains_transparent.pass.cpp | 70 ++ .../flat.set.operations/count.pass.cpp | 69 ++ .../count_transparent.pass.cpp | 71 ++ .../flat.set.operations/equal_range.pass.cpp | 77 ++ .../equal_range_transparent.pass.cpp | 97 ++ .../flat.set.operations/find.pass.cpp | 53 ++ .../find_transparent.pass.cpp | 88 ++ .../flat.set.operations/lower_bound.pass.cpp | 70 ++ .../lower_bound_transparent.pass.cpp | 94 ++ .../flat.set.operations/upper_bound.pass.cpp | 71 ++ .../upper_bound_transparent.pass.cpp | 93 ++ .../container.adaptors/flat.set/helpers.h | 294 ++++++ .../flat.set/incomplete_type.pass.cpp | 33 + .../flat.set/op_compare.pass.cpp | 105 +++ .../flat.set/types.compile.pass.cpp | 94 ++ 82 files changed, 8453 insertions(+) create mode 100644 libcxx/include/__flat_set/flat_set.h create mode 100644 libcxx/include/flat_set create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/helpers.h create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8dac823503d73f..75acf9f7899ff6 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -367,6 +367,7 @@ set(files __flat_map/sorted_equivalent.h __flat_map/sorted_unique.h __flat_map/utils.h + __flat_set/flat_set.h __format/buffer.h __format/concepts.h __format/container_adaptor.h @@ -986,6 +987,7 @@ set(files fenv.h filesystem flat_map + flat_set float.h format forward_list diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h new file mode 100644 index 00000000000000..c920632c453bf5 --- /dev/null +++ b/libcxx/include/__flat_set/flat_set.h @@ -0,0 +1,853 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FLAT_set_FLAT_SET_H +#define _LIBCPP___FLAT_set_FLAT_SET_H + +#include <__algorithm/lexicographical_compare_three_way.h> +#include <__algorithm/min.h> +#include <__algorithm/ranges_adjacent_find.h> +#include <__algorithm/ranges_equal.h> +#include <__algorithm/ranges_inplace_merge.h> +#include <__algorithm/ranges_lower_bound.h> +#include <__algorithm/ranges_partition_point.h> +#include <__algorithm/ranges_sort.h> +#include <__algorithm/ranges_unique.h> +#include <__algorithm/ranges_upper_bound.h> +#include <__algorithm/remove_if.h> +#include <__assert> +#include <__compare/synth_three_way.h> +#include <__concepts/swappable.h> +#include <__config> +#include <__cstddef/byte.h> +#include <__cstddef/ptrdiff_t.h> +#include <__flat_map/sorted_unique.h> +#include <__functional/invoke.h> +#include <__functional/is_transparent.h> +#include <__functional/operations.h> +#include <__fwd/vector.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/ranges_iterator_traits.h> +#include <__iterator/reverse_iterator.h> +#include <__memory/allocator_traits.h> +#include <__memory/uses_allocator.h> +#include <__memory/uses_allocator_construction.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/container_compatible_range.h> +#include <__ranges/drop_view.h> +#include <__ranges/from_range.h> +#include <__ranges/ref_view.h> +#include <__ranges/size.h> +#include <__ranges/subrange.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/container_traits.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_allocator.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_same.h> +#include <__utility/exception_guard.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include <__utility/scope_guard.h> +#include <__vector/vector.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template , class _KeyContainer = vector<_Key>> +class flat_set { + template + friend class flat_set; + + static_assert(is_same_v<_Key, typename _KeyContainer::value_type>); + static_assert(!is_same_v<_KeyContainer, std::vector>, "vector is not a sequence container"); + +public: + // types + using key_type = _Key; + using value_type = _Key; + using key_compare = __type_identity_t<_Compare>; + using value_compare = _Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename _KeyContainer::size_type; + using difference_type = typename _KeyContainer::difference_type; + using iterator = typename _KeyContainer::const_iterator; + using const_iterator = iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using container_type = _KeyContainer; + +private: + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = + uses_allocator::value; + + _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; + +public: + // [flat.set.cons], construct/copy/destroy + _LIBCPP_HIDE_FROM_ABI + flat_set() noexcept(is_nothrow_default_constructible_v<_KeyContainer> && is_nothrow_default_constructible_v<_Compare>) + : __keys_(), __compare_() {} + + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other) noexcept( + is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : __keys_(std::move(__other.__keys_)), __compare_(std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + // gcc does not like the `throw` keyword in a conditionally noexcept function + if constexpr (!(is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>)) { + throw; + } +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const key_compare& __comp) : __keys_(), __compare_(__comp) {} + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + __sort_and_unique(); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(), __compare_(__comp) { + insert(__first, __last); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(__first, __last), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg) + : flat_set(from_range, std::forward<_Range>(__rg), key_compare()) {} + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp) : flat_set(__comp) { + insert_range(std::forward<_Range>(__rg)); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(__il.begin(), __il.end(), __comp) {} + + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : flat_set(__ctor_uses_allocator_tag{}, __alloc, std::move(__other.__keys_), std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + throw; +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(sorted_unique, __first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, + _InputIterator __first, + _InputIterator __last, + const key_compare& __comp, + const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(sorted_unique, __first, __last); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert_range(std::forward<_Range>(__rg)); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert_range(std::forward<_Range>(__rg)); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(initializer_list __il) { + clear(); + insert(__il); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(flat_set&& __other) noexcept( + is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_Compare>) { + // No matter what happens, we always want to clear the other container before returning + // since we moved from it + auto __clear_other_guard = std::__make_scope_guard([&]() noexcept { __other.clear() /* noexcept */; }); + { + // If an exception is thrown, we have no choice but to clear *this to preserve invariants + auto __on_exception = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__other.__keys_); + __compare_ = std::move(__other.__compare_); + __on_exception.__complete(); + } + return *this; + } + + // iterators + _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + + _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return begin(); } + _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return end(); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + // [flat.set.capacity], capacity + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __keys_.empty(); } + + _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __keys_.size(); } + + _LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept { return __keys_.max_size(); } + + // [flat.set.modifiers], modifiers + template + _LIBCPP_HIDE_FROM_ABI pair emplace(_Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __try_emplace(std::forward<_Args>(__args)...); + } else { + return __try_emplace(_Key(std::forward<_Args>(__args)...)); + } + } + + template + _LIBCPP_HIDE_FROM_ABI iterator emplace_hint(const_iterator __hint, _Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __emplace_hint(std::move(__hint), std::forward<_Args>(__args)...); + } else { + return __emplace_hint(std::move(__hint), _Key(std::forward<_Args>(__args)...)); + } + } + + _LIBCPP_HIDE_FROM_ABI pair insert(const value_type& __x) { return emplace(__x); } + + _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { + return emplace(std::forward<_Kp>(__x)); + } + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, const value_type& __x) { + return emplace_hint(__hint, __x); + } + + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, value_type&& __x) { + return emplace_hint(__hint, std::move(__x)); + } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { + return emplace_hint(__hint, std::forward<_Kp>(__x)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, _InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { + if constexpr (ranges::sized_range<_Range>) { + __reserve(ranges::size(__range)); + } + + __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + } + + _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } + + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, initializer_list __il) { + insert(sorted_unique, __il.begin(), __il.end()); + } + + _LIBCPP_HIDE_FROM_ABI container_type extract() && { + auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; }); + auto __ret = std::move(__keys_); + return __ret; + } + + _LIBCPP_HIDE_FROM_ABI void replace(container_type&& __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys), "Either the key container is not sorted or it contains duplicates"); + auto __guard = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__keys); + __guard.__complete(); + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __position) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_iter = __keys_.erase(__position); + __on_failure.__complete(); + return __key_iter; + } + + // The following overload is the same as the iterator overload + // iterator erase(const_iterator __position); + + _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __x) { + auto __iter = find(__x); + if (__iter != end()) { + erase(__iter); + return 1; + } + return 0; + } + + template + requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + !is_convertible_v<_Kp &&, const_iterator>) + _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { + auto [__first, __last] = equal_range(__x); + auto __res = __last - __first; + erase(__first, __last); + return __res; + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_it = __keys_.erase(__first, __last); + __on_failure.__complete(); + return __key_it; + } + + _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __y) noexcept { + // warning: The spec has unconditional noexcept, which means that + // if any of the following functions throw an exception, + // std::terminate will be called. + // This is discussed in P2767, which hasn't been voted on yet. + ranges::swap(__compare_, __y.__compare_); + ranges::swap(__keys_, __y.__keys_); + } + + _LIBCPP_HIDE_FROM_ABI void clear() noexcept { __keys_.clear(); } + + // observers + _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __compare_; } + _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __compare_; } + + // set operations + _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __x) { return __find_impl(*this, __x); } + + _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { + return __find_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { + return __find_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { + return contains(__x) ? 1 : 0; + } + + _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { + return find(__x) != end(); + } + + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) { + return __equal_range_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) const { + return __equal_range_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { + return __equal_range_impl(*this, __x); + } + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { + return __equal_range_impl(*this, __x); + } + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const flat_set& __x, const flat_set& __y) { + return ranges::equal(__x, __y); + } + + friend _LIBCPP_HIDE_FROM_ABI auto operator<=>(const flat_set& __x, const flat_set& __y) { + return std::lexicographical_compare_three_way( + __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); + } + + friend _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __x, flat_set& __y) noexcept { __x.swap(__y); } + +private: + struct __ctor_uses_allocator_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_tag() = default; + }; + struct __ctor_uses_allocator_empty_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_empty_tag() = default; + }; + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), + __compare_(std::forward<_CompArg>(__comp)...) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc)), + __compare_(std::forward<_CompArg>(__comp)...) {} + + _LIBCPP_HIDE_FROM_ABI bool __is_sorted_and_unique(auto&& __key_container) const { + auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) { return !__compare_(__x, __y); }; + return ranges::adjacent_find(__key_container, __greater_or_equal_to) == ranges::end(__key_container); + } + + // This function is only used in constructors. So there is not exception handling in this function. + // If the function exits via an exception, there will be no flat_set object constructed, thus, there + // is no invariant state to preserve + _LIBCPP_HIDE_FROM_ABI void __sort_and_unique() { + ranges::sort(__keys_, __compare_); + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } else { + for (; __first != __last; ++__first) { + __keys_.insert(__keys_.end(), *__first); + } + } + if (size() != __old_size) { + if constexpr (!_WasSorted) { + ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); + } else { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__is_sorted_and_unique(__keys_ | ranges::views::drop(__old_size)), + "Either the key container is not sorted or it contains duplicates"); + } + ranges::inplace_merge(__keys_.begin(), __keys_.begin() + __old_size, __keys_.end(), __compare_); + + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + __on_failure.__complete(); + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __find_impl(_Self&& __self, const _Kp& __key) { + auto __it = __self.lower_bound(__key); + auto __last = __self.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return __last; + } + return __it; + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __equal_range_impl(_Self&& __self, const _Kp& __key) { + auto __it = ranges::lower_bound(__self.__keys_, __key, __self.__compare_); + auto __last = __self.__keys_.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return std::make_pair(__it, __it); + } + return std::make_pair(__it, std::next(__it)); + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_exact_pos(const_iterator __it, _KeyArg&& __key) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { + if constexpr (!__container_traits<_KeyContainer>::__emplacement_has_strong_exception_safety_guarantee) { + clear() /* noexcept */; + } + }); + auto __key_it = __keys_.emplace(__it, std::forward<_KeyArg>(__key)); + __on_failure.__complete(); + return __key_it; + } + + template + _LIBCPP_HIDE_FROM_ABI pair __try_emplace(_Kp&& __key) { + auto __it = lower_bound(__key); + if (__it == end() || __compare_(__key, *__it)) { + return pair(__emplace_exact_pos(__it, std::forward<_Kp>(__key)), true); + } else { + return pair(std::move(__it), false); + } + } + + template + _LIBCPP_HIDE_FROM_ABI bool __is_hint_correct(const_iterator __hint, _Kp&& __key) { + if (__hint != cbegin() && !__compare_(*(__hint - 1), __key)) { + return false; + } + if (__hint != cend() && __compare_(*__hint, __key)) { + return false; + } + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint(const_iterator __hint, _Kp&& __key) { + if (__is_hint_correct(__hint, __key)) { + if (__hint == cend() || __compare_(__key, *__hint)) { + return __emplace_exact_pos(__hint, std::forward<_Kp>(__key)); + } else { + // key equals + return __hint; + } + } else { + return __try_emplace(std::forward<_Kp>(__key)).first; + } + } + + _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __size) { + if constexpr (requires { __keys_.reserve(__size); }) { + __keys_.reserve(__size); + } + } + + template + friend typename flat_set<_Key2, _Compare2, _KeyContainer2>::size_type + erase_if(flat_set<_Key2, _Compare2, _KeyContainer2>&, _Predicate); + + _KeyContainer __keys_; + _LIBCPP_NO_UNIQUE_ADDRESS key_compare __compare_; + + struct __key_equiv { + _LIBCPP_HIDE_FROM_ABI __key_equiv(key_compare __c) : __comp_(__c) {} + _LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const { + return !__comp_(__x, __y) && !__comp_(__y, __x); + } + key_compare __comp_; + }; +}; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(_KeyContainer, _Compare = _Compare()) -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(_KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(_KeyContainer, _Compare, _Allocator) -> flat_set; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare = _Compare()) + -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(sorted_unique_t, _KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare, _Allocator) + -> flat_set; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(_InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >, + class _Allocator = allocator, + class = __enable_if_t::value && __is_allocator<_Allocator>::value>> +flat_set(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> flat_set< + ranges::range_value_t<_Range>, + _Compare, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template ::value>> +flat_set(from_range_t, _Range&&, _Allocator) -> flat_set< + ranges::range_value_t<_Range>, + less>, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template +struct uses_allocator, _Allocator> + : bool_constant> {}; + + template + _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type + erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; + } + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FLAT_set_FLAT_SET_H diff --git a/libcxx/include/flat_set b/libcxx/include/flat_set new file mode 100644 index 00000000000000..d03645fafafdba --- /dev/null +++ b/libcxx/include/flat_set @@ -0,0 +1,59 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_FLAT_SET +#define _LIBCPP_FLAT_SET + +/* + Header synopsis + +#include // see [compare.syn] +#include // see [initializer.list.syn] + +namespace std { + // [flat.set], class template flat_set + template, class KeyContainer = vector> + class flat_set; + + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + + template + struct uses_allocator, Allocator>; + + // [flat.set.erasure], erasure for flat_set + template + typename flat_set::size_type + erase_if(flat_set& c, Predicate pred); +} +*/ + +#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +# include <__cxx03/__config> +#else +# include <__config> + +# if _LIBCPP_STD_VER >= 23 +# include <__flat_map/sorted_unique.h> +# include <__flat_set/flat_set.h> +# endif + +// for feature-test macros +# include + +// standard required includes +# include +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif +#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) + +#endif // _LIBCPP_FLAT_SET diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4bae02137b37b2..abc351d5923963 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1263,6 +1263,17 @@ module std [system] { export * } + module flat_set { + module flat_set { + header "__flat_set/flat_set.h" + export std.vector.vector + export std.vector.fwd + } + + header "flat_set" + export * + } + module format { module buffer { header "__format/buffer.h" diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp new file mode 100644 index 00000000000000..204df1d681af1b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m; + ASSERT_SAME_TYPE(decltype(m.empty()), bool); + ASSERT_NOEXCEPT(m.empty()); + assert(m.empty()); + assert(std::as_const(m).empty()); + m = {1}; + assert(!m.empty()); + m.clear(); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp new file mode 100644 index 00000000000000..161fe533eabacb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include + +void f() { + std::flat_set c; + c.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp new file mode 100644 index 00000000000000..cd7f424e00ece2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type max_size() const noexcept; + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_allocator.h" +#include "test_macros.h" + +int main(int, char**) { + { + using A1 = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= 10); + LIBCPP_ASSERT(c.max_size() == 10); + } + { + using A = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + LIBCPP_ASSERT(c.max_size() == max_dist); + } + { + typedef std::flat_set C; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + assert(c.max_size() <= alloc_max_size(std::allocator())); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp new file mode 100644 index 00000000000000..7c156e95ecb1c8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type size() const noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using M = std::flat_set, KeyContainer>; + using S = typename M::size_type; + { + const M m = {1, 1, 4, 5, 5}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 3); + } + { + const M m = {1}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 1); + } + { + const M m; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 0); + } + { + M m; + S s = 1000000; + for (auto i = 0u; i < s; ++i) { + m.emplace(i); + } + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == s); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp new file mode 100644 index 00000000000000..acc0817d7cac4d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// explicit flat_set(const Allocator& a); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // explicit + using M = std::flat_set, std::vector>>; + + static_assert(std::is_constructible_v>); + static_assert(!std::is_convertible_v, M>); + } + { + using A = test_allocator; + using M = std::flat_set, std::vector>>; + M m(A(0, 5)); + assert(m.empty()); + assert(m.begin() == m.end()); + auto v = std::move(m).extract(); + assert(v.get_allocator().get_id() == 5); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp new file mode 100644 index 00000000000000..7f75f1e1611e3b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(initializer_list il); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m = {8, 10}; + assert(m.size() == 2); + m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + int expected[] = {1, 2, 3, 4, 5, 6}; + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + } + { + M m = {10, 8}; + assert(m.size() == 2); + m = {3}; + int expected[] = {3}; + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp new file mode 100644 index 00000000000000..b3bee18f5a936b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(const key_compare& comp); +// template +// flat_set(const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + auto m = std::flat_set(C(3)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(3)); + } + { + // The one-argument ctor is explicit. + using C = test_less; + static_assert(std::is_constructible_v, C>); + static_assert(!std::is_convertible_v>); + + static_assert(std::is_constructible_v, std::less>); + static_assert(!std::is_convertible_v, std::flat_set>); + } + { + using C = test_less; + using A1 = test_allocator; + auto m = std::flat_set>(C(4), A1(5)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + { + // explicit(false) + using C = test_less; + using A1 = test_allocator; + std::flat_set> m = {C(4), A1(5)}; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp new file mode 100644 index 00000000000000..3d1e6240c952e8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -0,0 +1,158 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(container_type key_cont, const key_compare& comp = key_compare()); +// template +// flat_set(const container_type& key_cont, const Allocator& a); +// template +// flat_set(const container_type& key_cont, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(container_type) + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + + // explicit + static_assert(std::is_constructible_v&>); + static_assert(!ImplicitlyConstructible&>); + } + { + // flat_set(container_type) + // move-only + MoveOnly expected[] = {3, 2, 1}; + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks; + ks.push_back(1); + ks.push_back(3); + ks.push_back(2); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(container_type) + // container's allocator is used + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(5)); + } + { + // flat_set(container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + + // explicit + static_assert(std::is_constructible_v&, const C&>); + static_assert(!ImplicitlyConstructible&, const C&>); + } + { + // flat_set(container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(ks, A(4)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , const Allocator&) + // explicit(false) + using A = test_allocator; + using M = std::flat_set, std::deque>; + static_assert(ImplicitlyConstructible&, const A&>); + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + M m = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4), A(5)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + auto m_copy = m; + auto keys = std::move(m_copy).extract(); + assert(keys.get_allocator() == A(5)); + + // explicit(false) + static_assert(ImplicitlyConstructible&, const A&>); + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + keys = std::move(m2).extract(); + assert(keys.get_allocator() == A(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp new file mode 100644 index 00000000000000..f1dbc955e1b0de --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(-2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp new file mode 100644 index 00000000000000..59fb9d0a38366f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M(mo, test_allocator(3)); + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(3)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp new file mode 100644 index 00000000000000..169b469f3bca68 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& s); + +// Validate whether the container can be copy-assigned (move-assigned, swapped) +// with an ADL-hijacking operator& + +#include +#include + +#include "test_macros.h" +#include "operator_hijacker.h" + +void test() { + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp new file mode 100644 index 00000000000000..cdd5045f4bb9f7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // test_allocator is not propagated + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M({{3, 4, 5}}, C(3), test_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + // other_allocator is propagated + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = M({3, 4, 5}, C(3), other_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + { + // comparator is copied and invariant is preserved + using M = std::flat_set>; + M mo = M({1, 2}, std::less()); + M m = M({1, 2}, std::greater()); + assert(m.key_comp()(2, 1) == true); + assert(m != mo); + m = mo; + assert(m.key_comp()(2, 1) == false); + assert(m == mo); + } + { + // self-assignment + using M = std::flat_set; + M m = {{1, 2}}; + m = static_cast(m); + assert((m == M{{1, 2}})); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp new file mode 100644 index 00000000000000..5db8c4ca722466 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Test CTAD on cases where deduction should fail. + +#include +#include +#include +#include +#include + +struct NotAnAllocator { + friend bool operator<(NotAnAllocator, NotAnAllocator) { return false; } +}; + +template +concept CanDeductFlatSet = requires { std::flat_set{std::declval()...}; }; + +static_assert(CanDeductFlatSet, std::vector>); + +// cannot deduce Key and T from nothing +static_assert(!CanDeductFlatSet<>); + +// cannot deduce Key and T from just (KeyContainer), even if it's a container of pairs +static_assert(!CanDeductFlatSet>>); + +// cannot deduce Key and T from just (KeyContainer, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>>); + +// cannot deduce Key and T from just (Compare) +static_assert(!CanDeductFlatSet>); + +// cannot deduce Key and T from just (Compare, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>); + +// cannot deduce Key and T from just (Allocator) +static_assert(!CanDeductFlatSet>); + +// cannot convert from some arbitrary unrelated type +static_assert(!CanDeductFlatSet); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp new file mode 100644 index 00000000000000..612e64a7c42f23 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -0,0 +1,341 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "deduction_guides_sfinae_checks.h" +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_copy() { + { + std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set s(source); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s{source}; // braces instead of parens + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s(source, std::allocator()); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } +} + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(ks, vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(ks, vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_iter_iter() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m(std::begin(arr), std::end(arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) + static_assert(std::is_same_v>); + assert(s.size() == 3); + } +} + +void test_iter_iter_compare() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m(std::begin(arr), std::end(arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } +} + +void test_initializer_list() { + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } + { + using M = std::flat_set; + M m; + std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + assert(s[m] == m); + } +} + +void test_initializer_list_compare() { + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } +} + +void test_from_range() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(std::from_range, r); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +void test_from_range_compare() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(std::from_range, r, std::greater()); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +int main(int, char**) { + // Each test function also tests the sorted_unique-prefixed and allocator-suffixed overloads. + test_copy(); + test_containers(); + test_containers_compare(); + test_iter_iter(); + test_iter_iter_compare(); + test_initializer_list(); + test_initializer_list_compare(); + test_from_range(); + test_from_range_compare(); + + AssociativeContainerDeductionGuidesSfinaeAway>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp new file mode 100644 index 00000000000000..df8d6d885ee524 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + const int expected[] = {1, 2, 3, INT_MAX}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + const int expected[] = {INT_MAX, 3, 2, 1}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +int main(int, char**) { + test_containers(); + test_containers_compare(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp new file mode 100644 index 00000000000000..64b0bfcb383a72 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + std::flat_set m; + assert(m.empty()); + } + { + // explicit(false) + std::flat_set m = {}; + assert(m.empty()); + } + { + std::flat_set>> m; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp().default_constructed_); + } + { + using A1 = explicit_allocator; + using A2 = explicit_allocator; + { + std::flat_set> m; + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + { + A1 a1; + std::flat_set> m(a1); + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp new file mode 100644 index 00000000000000..b4a3b6de205a31 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set() +// noexcept( +// is_nothrow_default_constructible_v && +// is_nothrow_default_constructible_v); + +// This tests a conforming extension + +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +int main(int, char**) { +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp new file mode 100644 index 00000000000000..c0d315c0ce74b4 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// ~flat_set(); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingDtorComp { + bool operator()(const auto&, const auto&) const; + ~ThrowingDtorComp() noexcept(false) {} +}; + +int main(int, char**) { + { + using C = std::flat_set; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::vector>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::deque>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(!std::is_nothrow_destructible_v); + C c; + } +#endif // _LIBCPP_VERSION + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp new file mode 100644 index 00000000000000..cd2319e91f760d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -0,0 +1,151 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(initializer_list il, const key_compare& comp = key_compare()); +// template +// flat_set(initializer_list il, const Alloc& a); +// template +// flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +#include "../../../test_compare.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + } + + int expected[] = {1, 2, 3, 5}; + { + // flat_set(initializer_list); + using M = std::flat_set; + std::initializer_list il = {5, 2, 2, 3, 1, 3}; + M m(il); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + // explicit(false) + using M = std::flat_set; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + using M = std::flat_set, std::deque>>; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + { + using A = explicit_allocator; + { + // flat_set(initializer_list); + // different comparator + using M = std::flat_set>; + M m = {1, 2, 3}; + assert(m.size() == 1); + LIBCPP_ASSERT(*m.begin() == 1); + assert(m.key_comp().default_constructed_); + } + { + // flat_set(initializer_list, const Allocator&); + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + } + { + // flat_set(initializer_list, const key_compare&); + using C = test_less; + using M = std::flat_set; + auto m = M({5, 2, 2, 3, 1, 3}, C(10)); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + assert(m.key_comp() == C(10)); + + // explicit(false) + M m2 = {{5, 2, 2, 1, 3, 3}, C(10)}; + assert(m2 == m); + assert(m2.key_comp() == C(10)); + } + { + // flat_set(initializer_list, const key_compare&); + // Sorting uses the comparator that was passed in + using M = std::flat_set, std::deque>>; + auto m = M({5, 2, 2, 1, 3, 1}, std::greater()); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + assert(m.key_comp()(2, 1) == true); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using A = explicit_allocator; + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, {}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp new file mode 100644 index 00000000000000..65eebc21a66c4c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(InputIterator first, InputIterator last, const Allocator& a); +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(InputIterator , InputIterator) + // cpp17_input_iterator + using M = std::flat_set; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)}; + assert(m2 == m); + } + { + // flat_set(InputIterator , InputIterator) + // greater + using M = std::flat_set, std::deque>>; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(InputIterator , InputIterator) + // Test when the operands are of array type (also contiguous iterator type) + using M = std::flat_set, std::vector>>; + auto m = M(ar, ar); + assert(m.empty()); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&) + using C = test_less; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {ar, ar + 9, C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + auto m = M(ar, ar + 9, A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + M m = {ar, ar + 9, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {ar, ar + 9, {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp new file mode 100644 index 00000000000000..69b340ad09fe15 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A(7)); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A(7)); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().get_id() == test_alloc_base::moved_value); + } + { + using C = test_less; + using A = min_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A()); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A()); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A()); + } + { + // A moved-from flat_set maintains its class invariant in the presence of moved-from comparators. + using M = std::flat_set>; + M mo = M({1, 2, 3}, std::less()); + M m = std::move(mo); + assert(m.size() == 3); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.key_comp()(1, 2) == true); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + LIBCPP_ASSERT(m.key_comp()(1, 2) == true); + LIBCPP_ASSERT(mo.empty()); + mo.insert({1, 2, 3}); // insert has no preconditions + assert(m == mo); + } + { + // moved-from object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m1.size() == 0); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp new file mode 100644 index 00000000000000..fc7f68d8c967ad --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + int expected[] = {1, 2, 3}; + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + auto mo = M(expected, expected + 3, C(5), A(7)); + auto m = M(std::move(mo), A(3)); + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(3)); + assert(std::ranges::equal(keys, expected )); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A(7)); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2(std::move(m1), std::allocator{}); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp new file mode 100644 index 00000000000000..b16dc38dd40285 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{4, 5})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + m = std::move(mo); + assert((m == M{5, 4, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A()); + assert(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp new file mode 100644 index 00000000000000..50817f4be8a812 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); +// Preserves the class invariant for the moved-from flat_set. + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +int main(int, char**) { + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp new file mode 100644 index 00000000000000..86f3568f0d67a6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&& c) +// noexcept( +// is_nothrow_move_assignable::value && +// is_nothrow_move_assignable::value && +// is_nothrow_copy_assignable::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_macros.h" + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp new file mode 100644 index 00000000000000..17e4e40387606c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// flat_set(flat_set&& s); +// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +int main(int, char**) { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp new file mode 100644 index 00000000000000..49d1151fd8a993 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&) +// noexcept(is_nothrow_move_constructible::value && +// is_nothrow_move_constructible::value && +// is_nothrow_copy_constructible::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp new file mode 100644 index 00000000000000..785718d2eed333 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -0,0 +1,322 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +// Test various constructors with pmr + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // flat_set(const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::polymorphic_allocator pa = &mr; + auto m1 = M(pa); + assert(m1.empty()); + assert(std::move(m1).extract().get_allocator() == pa); + auto m2 = M(&mr); + assert(m2.empty()); + assert(std::move(m2).extract().get_allocator() == pa); + } + { + // flat_set(const key_compare& comp, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::greater()); + assert(vm[0] == M{}); + assert(vm[0].key_comp()(2, 1) == true); + assert(vm[0].value_comp()(2, 1) == true); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + // const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + assert(ks.get_allocator().resource() != &mr); + vm.emplace_back(ks); + assert(ks.size() == 9); // ks' value is unchanged, since it was an lvalue above + assert((vm[0] == M{1, 2, 3})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const flat_set&, const allocator_type&); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, C(5), &mr1); + M m = {mo, &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + auto keys = std::move(m).extract(); + assert((keys == std::pmr::vector{1, 2, 3})); + assert(keys.get_allocator().resource() == &mr2); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + auto keys2 = std::move(mo).extract(); + assert((keys2 == std::pmr::vector{1, 2, 3})); + assert(keys2.get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set&, const allocator_type&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::vector vs; + M m = {1, 2, 3}; + vs.push_back(m); + assert(vs[0] == m); + } + { + // flat_set& operator=(const flat_set& m); + // pmr allocator is not propagated + using M = std::flat_set, std::pmr::deque>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, &mr1); + M m = M({4, 5}, &mr2); + m = mo; + assert((m == M{1, 2, 3})); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // mo is unchanged + assert((mo == M{1, 2, 3})); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set& m); + using C = test_less; + std::pmr::monotonic_buffer_resource mr; + using M = std::flat_set>; + auto mo = M({1, 2, 3}, C(5), &mr); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert((m == M{1, 2, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator().resource() == std::pmr::get_default_resource()); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert((mo == M{1, 2, 3})); + auto kso = std::move(mo).extract(); + assert(kso.get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il, C(5)); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + assert(vm[0].key_comp() == C(5)); + } + { + // flat_set(InputIterator first, InputIterator last, const Allocator& a); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // cpp17 iterator + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(ar, ar); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(flat_set&&, const allocator_type&); + int expected[] = {1, 2, 3}; + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 3, 1, 2}, C(5), &mr1); + M m = {std::move(mo), &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + assert(std::equal(m.begin(), m.end(), expected, expected + 3)); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(flat_set&&, const allocator_type&); + using M = std::flat_set, std::pmr::deque>; + std::pmr::vector vs; + M m = {1, 3, 1, 2}; + vs.push_back(std::move(m)); + assert((std::move(vs[0]).extract() == std::pmr::deque{1, 2, 3})); + } + { + // flat_set& operator=(flat_set&&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = + M({"short", "very long string that definitely won't fit in the SSO buffer and therefore becomes empty on move"}, + &mr1); + M m = M({"don't care"}, &mr2); + m = std::move(mo); + assert(m.size() == 2); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.begin()->get_allocator().resource() == &mr2); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + mo.insert("foo"); + assert(mo.begin()->get_allocator().resource() == &mr1); + } + { + // flat_set(from_range_t, R&&, const Alloc&); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // input_range + using M = std::flat_set, std::pmr::vector>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(ar, ar)); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 2, 4, 10}; + vm.emplace_back(std::sorted_unique, ks); + assert(!ks.empty()); // it was an lvalue above + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, const container_type& key_cont,const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks({1, 2, 4, 10}, &mr); + vm.emplace_back(std::sorted_unique, ks); + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp new file mode 100644 index 00000000000000..bb9f99c228bfec --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -0,0 +1,173 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// flat_set(from_range_t, R&&) +// template R> +// flat_set(from_range_t, R&&, const key_compare&) +// template R, class Alloc> +// flat_set(from_range_t, R&&, const Alloc&); +// template R, class Alloc> +// flat_set(from_range_t, R&&, const key_compare&, const Alloc&); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +// test constraint container-compatible-range + +template +using RangeOf = std::ranges::subrange; +using Set = std::flat_set; + +static_assert(std::is_constructible_v>); +static_assert(std::is_constructible_v>); +static_assert(!std::is_constructible_v>>); + +static_assert(std::is_constructible_v, std::less>); +static_assert(std::is_constructible_v, std::less>); +static_assert(!std::is_constructible_v>, std::less>); + +static_assert(std::is_constructible_v, std::allocator>); +static_assert(std::is_constructible_v, std::allocator>); +static_assert(!std::is_constructible_v>, std::allocator>); + +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert( + !std:: + is_constructible_v>, std::less, std::allocator>); + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(from_range_t, R&&) + // input_range && !common + using M = std::flat_set; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))}; + assert(m2 == m); + } + { + // flat_set(from_range_t, R&&) + // greater + using M = std::flat_set, std::deque>>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(from_range_t, R&&) + // contiguous range + using M = std::flat_set; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9)); + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(from_range_t, R&&, const key_compare&) + using C = test_less; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {std::from_range, R(ar, ar + 9), C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp new file mode 100644 index 00000000000000..2d442d49667bd0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(sorted_unique_t, container_type key_cont, const key_compare& comp = key_compare()); +// +// template +// flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); +// template +// flat_set(sorted_unique_t, const container_type& key_cont, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, container_type) + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + auto ks2 = ks; + + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + + // explicit(false) + M m2 = {std::sorted_unique, std::move(ks2)}; + assert(m == m2); + } + { + // flat_set(sorted_unique_t, container_type) + // non-default container, comparator and allocator type + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks = {10, 4, 2, 1}; + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + } + { + // flat_set(sorted_unique_t, container_type) + // allocator copied into the containers + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + assert(std::move(m).extract().get_allocator() == A(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + + auto m = M(std::sorted_unique, ks, C(4)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, C(4)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 2, 4, 10}; + auto m = M(std::sorted_unique, ks, C(4), A(5)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + assert(M(m).extract().get_allocator() == A(5)); + + // explicit(false) + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + assert(std::move(m2).extract().get_allocator() == A(5)); + } + { + // flat_set(sorted_unique_t, container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, ks, A(6)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 4, 10})); + assert(M(m).extract().get_allocator() == A(6)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, A(6)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp new file mode 100644 index 00000000000000..01956a78c7f48d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t s, initializer_list il, +// const key_compare& comp = key_compare()) +// template +// flat_set(sorted_unique_t, initializer_list il, const Alloc& a); +// template +// flat_set(sorted_unique_t, initializer_list il, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +std::initializer_list il = {1, 2, 4, 5}; + +const auto il1 = il; +const auto il2 = il; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + } + + { + // flat_set(sorted_unique_t, initializer_list); + using M = std::flat_set; + auto m = M(std::sorted_unique, il1); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, il1}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + using M = std::flat_set>; + auto m = M(std::sorted_unique, il1, std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, il1, std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + std::initializer_list il4{5, 4, 2, 1}; + auto m = M(std::sorted_unique, il4, std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, initializer_list, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + auto m = M(std::sorted_unique, il2, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, il2, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(std::sorted_unique, il2, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {std::sorted_unique, il2, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp new file mode 100644 index 00000000000000..b5229a84dd5133 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // cpp17_input_iterator + using M = std::flat_set; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // cpp_17_input_iterator + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + int ar[] = {5, 4, 2, 1}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[1] = {42}; + auto m = M(std::sorted_unique, ar, ar, C(5)); + assert(m.empty()); + assert(m.key_comp() == C(5)); + } + { + // flat_set(sorted_unique_t, InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, ar, ar + 4, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + int ar[] = {1, 2, 4, 5}; + M m = {std::sorted_unique, ar, ar + 4, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp new file mode 100644 index 00000000000000..134db83aef3cad --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "min_allocator.h" + +// Verify that `flat_set` (like `set`) does NOT support std::erase. +// +template +concept HasStdErase = requires(S& s, typename S::value_type x) { std::erase(s, x); }; +static_assert(HasStdErase>); +static_assert(!HasStdErase>); + +template +M make(std::initializer_list vals) { + M ret; + for (int v : vals) + ret.emplace(v); + return ret; +} + +template +void test0( + std::initializer_list vals, Pred p, std::initializer_list expected, std::size_t expected_erased_count) { + M s = make(vals); + ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p))); + assert(expected_erased_count == std::erase_if(s, p)); + assert(s == make(expected)); +} + +template +void test() { + // Test all the plausible signatures for this predicate. + auto is1 = [](typename S::const_reference v) { return v == 1; }; + auto is2 = [](typename S::value_type v) { return v == 2; }; + auto is3 = [](const typename S::value_type& v) { return v == 3; }; + auto is4 = [](auto v) { return v == 4; }; + auto True = [](const auto&) { return true; }; + auto False = [](auto&&) { return false; }; + + test0({}, is1, {}, 0); + + test0({1}, is1, {}, 1); + test0({1}, is2, {1}, 0); + + test0({1, 2}, is1, {2}, 1); + test0({1, 2}, is2, {1}, 1); + test0({1, 2}, is3, {1, 2}, 0); + + test0({1, 2, 3}, is1, {2, 3}, 1); + test0({1, 2, 3}, is2, {1, 3}, 1); + test0({1, 2, 3}, is3, {1, 2}, 1); + test0({1, 2, 3}, is4, {1, 2, 3}, 0); + + test0({1, 2, 3}, True, {}, 3); + test0({1, 2, 3}, False, {1, 2, 3}, 0); +} + +int main(int, char**) { + test>(); + test, std::vector>>>(); + test, std::vector>>>(); + test, std::deque>>>(); + test, std::deque>>>(); + test>(); + test>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp new file mode 100644 index 00000000000000..6bbe1ad4f01670 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -0,0 +1,128 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); +// If any member function in [flat.set.defn] exits via an exception, the invariant is restored. +// (This is not a member function, but let's respect the invariant anyway.) + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct Counter { + int c1, c2, throws; + void tick() { + c1 -= 1; + if (c1 == 0) { + c1 = c2; + throws += 1; + throw 42; + } + } +}; +Counter g_counter = {0, 0, 0}; + +struct ThrowingAssignment { + ThrowingAssignment(int i) : i_(i) {} + ThrowingAssignment(const ThrowingAssignment&) = default; + ThrowingAssignment& operator=(const ThrowingAssignment& rhs) { + g_counter.tick(); + i_ = rhs.i_; + g_counter.tick(); + return *this; + } + operator int() const { return i_; } + int i_; +}; + +struct ThrowingComparator { + bool operator()(const ThrowingAssignment& a, const ThrowingAssignment& b) const { + g_counter.tick(); + return a.i_ < b.i_; + } +}; + +struct ErasurePredicate { + bool operator()(const auto& x) const { return (3 <= x && x <= 5); } +}; + +int main(int, char**) { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + { + using M = std::flat_set; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + M m = M({1, 2, 3, 4, 5, 6, 7, 8}); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + + { + using M = std::flat_set>; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + std::deque container = {5, 6, 7, 8}; + container.insert(container.begin(), {1, 2, 3, 4}); + M m = M(std::move(container)); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp new file mode 100644 index 00000000000000..c07297a141ad10 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator begin() noexcept; +// const_iterator begin() const noexcept +// iterator end() noexcept; +// const_iterator end() const noexcept; +// +// const_iterator cbegin() const noexcept; +// const_iterator cend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.begin()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cbegin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.begin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(m.end()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cend()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.end()), typename M::const_iterator); + static_assert(noexcept(m.begin())); + static_assert(noexcept(cm.begin())); + static_assert(noexcept(m.cbegin())); + static_assert(noexcept(m.end())); + static_assert(noexcept(cm.end())); + static_assert(noexcept(m.cend())); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(std::distance(cm.begin(), cm.end()) == 4); + assert(std::distance(m.cbegin(), m.cend()) == 4); + typename M::iterator i; // default-construct + i = m.begin(); // move-assignment + typename M::const_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 1; j <= 4; ++j, ++i) { // pre-increment + assert(*i == j); // operator* + } + assert(i == m.end()); + for (int j = 4; j >= 1; --j) { + --i; // pre-decrement + assert((*i) == j); + } + assert(i == m.begin()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // N3644 testing + using C = std::flat_set; + C::iterator ii1{}, ii2{}; + C::iterator ii4 = ii1; + C::const_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp new file mode 100644 index 00000000000000..29441dcc57d40e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set iterators should be C++20 random access iterators + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using KI = typename KeyContainer::iterator; + using I = M::iterator; + using CI = M::const_iterator; + using RI = M::reverse_iterator; + using CRI = M::const_reverse_iterator; + + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + + M m = {1, 2, 3, 4}; + + I i1 = m.begin(); + I i2 = m.begin() + 1; + + assert(i1 == i1); + assert(!(i1 != i1)); + assert(i1 != i2); + assert(!(i1 == i2)); + assert(i1 < i2); + assert(!(i1 < i1)); + assert(i1 <= i1); + assert(i1 <= i2); + assert(!(i2 <= i1)); + assert(i2 > i1); + assert(!(i2 > i2)); + assert(i2 >= i1); + assert(i2 >= i2); + assert(!(i1 >= i2)); + + CI ci1 = m.cbegin(); + CI ci2 = m.cbegin() + 1; + assert(ci1 == ci1); + assert(!(ci1 != ci1)); + assert(ci1 != ci2); + assert(!(ci1 == ci2)); + assert(ci1 < ci2); + assert(!(ci1 < ci1)); + assert(ci1 <= ci1); + assert(ci1 <= ci2); + assert(!(ci2 <= ci1)); + assert(ci2 > ci1); + assert(!(ci2 > ci2)); + assert(ci2 >= ci1); + assert(ci2 >= ci2); + assert(!(ci1 >= ci2)); + + RI ri1 = m.rbegin(); + RI ri2 = m.rbegin() + 1; + assert(ri1 == ri1); + assert(!(ri1 != ri1)); + assert(ri1 != ri2); + assert(!(ri1 == ri2)); + assert(ri1 < ri2); + assert(!(ri1 < ri1)); + assert(ri1 <= ri1); + assert(ri1 <= ri2); + assert(!(ri2 <= ri1)); + assert(ri2 > ri1); + assert(!(ri2 > ri2)); + assert(ri2 >= ri1); + assert(ri2 >= ri2); + assert(!(ri1 >= ri2)); + + CRI cri1 = m.crbegin(); + CRI cri2 = m.crbegin() + 1; + assert(cri1 == cri1); + assert(!(cri1 != cri1)); + assert(cri1 != cri2); + assert(!(cri1 == cri2)); + assert(cri1 < cri2); + assert(!(cri1 < cri1)); + assert(cri1 <= cri1); + assert(cri1 <= cri2); + assert(!(cri2 <= cri1)); + assert(cri2 > cri1); + assert(!(cri2 > cri2)); + assert(cri2 >= cri1); + assert(cri2 >= cri2); + assert(!(cri1 >= cri2)); + + if constexpr (std::three_way_comparable) { + static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::same_as I()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as RI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + + assert(i1 <=> i1 == std::strong_ordering::equivalent); + assert(i1 <=> i2 == std::strong_ordering::less); + assert(i2 <=> i1 == std::strong_ordering::greater); + + assert(ci1 <=> ci1 == std::strong_ordering::equivalent); + assert(ci1 <=> ci2 == std::strong_ordering::less); + assert(ci2 <=> ci1 == std::strong_ordering::greater); + + assert(ri1 <=> ri1 == std::strong_ordering::equivalent); + assert(ri1 <=> ri2 == std::strong_ordering::less); + assert(ri2 <=> ri1 == std::strong_ordering::greater); + + assert(cri1 <=> cri1 == std::strong_ordering::equivalent); + assert(cri1 <=> cri2 == std::strong_ordering::less); + assert(cri2 <=> cri1 == std::strong_ordering::greater); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp new file mode 100644 index 00000000000000..35b45b6e797233 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator, const_iterator, reverse_iterator, const_reverse_iterator + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + using I = C::iterator; + using CI = C::const_iterator; + using RI = C::reverse_iterator; + using CRI = C::const_reverse_iterator; + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp new file mode 100644 index 00000000000000..4ec64e706b7021 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include +#include +#include +#include +#include +#include "MinSequenceContainer.h" +#include "min_allocator.h" + +template +void test() { + { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + + static_assert(std::same_as, typename C::iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(std::ranges::viewable_range); + + static_assert(std::same_as, typename C::const_iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(!std::ranges::viewable_range); + } +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp new file mode 100644 index 00000000000000..a16383cdcf5383 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// reverse_iterator rbegin() noexcept; +// const_reverse_iterator rbegin() const noexcept; +// reverse_iterator rend() noexcept; +// const_reverse_iterator rend() const noexcept; +// +// const_reverse_iterator crbegin() const noexcept; +// const_reverse_iterator crend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include + +#include "test_macros.h" +#include + +int main(int, char**) { + { + using M = std::flat_set, std::deque>; + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.rbegin()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.rend()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crend()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rend()), M::const_reverse_iterator); + static_assert(noexcept(m.rbegin())); + static_assert(noexcept(cm.rbegin())); + static_assert(noexcept(m.crbegin())); + static_assert(noexcept(m.rend())); + static_assert(noexcept(cm.rend())); + static_assert(noexcept(m.crend())); + assert(m.size() == 4); + assert(std::distance(m.rbegin(), m.rend()) == 4); + assert(std::distance(cm.rbegin(), cm.rend()) == 4); + assert(std::distance(m.crbegin(), m.crend()) == 4); + assert(std::distance(cm.crbegin(), cm.crend()) == 4); + M::reverse_iterator i; // default-construct + ASSERT_SAME_TYPE(decltype(*i), const int&); + i = m.rbegin(); // move-assignment + M::const_reverse_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 4; j >= 1; --j, ++i) { // pre-increment + assert(*i == j); + } + assert(i == m.rend()); + for (int j = 1; j <= 4; ++j) { + --i; // pre-decrement + assert(*i == j); + } + assert(i == m.rbegin()); + } + { + // N3644 testing + using C = std::flat_set; + C::reverse_iterator ii1{}, ii2{}; + C::reverse_iterator ii4 = ii1; + C::const_reverse_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp new file mode 100644 index 00000000000000..221a13fa057577 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// void clear() noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// test noexcept + +template +concept NoExceptClear = requires(T t) { + { t.clear() } noexcept; +}; + +static_assert(NoExceptClear>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptClear, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4, 5}; + assert(m.size() == 5); + ASSERT_NOEXCEPT(m.clear()); + ASSERT_SAME_TYPE(decltype(m.clear()), void); + m.clear(); + assert(m.size() == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp new file mode 100644 index 00000000000000..95f7a3c5f5d34a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -0,0 +1,141 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// pair emplace(Args&&... args); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the begin + M m = {3, 5, 6, 7}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted in the middle + M m = {0, 1, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the end + M m = {0, 1}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } + { + // key already exists and original at the begin + M m = {2, 3, 5, 6}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original in the middle + M m = {0, 2, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 1); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original at the end + M m = {0, 1, 2}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace()), R); + R r = m.emplace(2, 0.0); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace(1, 3.5); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace(1, 3.5); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp new file mode 100644 index 00000000000000..de855d5e5c3009 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// iterator emplace_hint(const_iterator position, Args&&... args); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace_hint(m.end(), typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + } + { + // hints correct at the begin + M m = {3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints correct at the end + M m = {0, 1}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct but key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the begin + M m = {1, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrectly in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 1; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the end + M m = {0, 3}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrect and key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace_hint(m.cbegin())), R); + R r = m.emplace_hint(m.end(), 2, 0.0); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp new file mode 100644 index 00000000000000..386af04d26e9a2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(iterator position); +// iterator erase(const_iterator position); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(std::next(m.cbegin(), 3)); + assert(m.size() == 7); + assert(i1 == std::next(m.begin(), 3)); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 5); + assert(*std::next(m.begin(), 4) == 6); + assert(*std::next(m.begin(), 5) == 7); + assert(*std::next(m.begin(), 6) == 8); + + std::same_as decltype(auto) i2 = m.erase(std::next(m.begin(), 0)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 5)); + assert(m.size() == 5); + assert(i3 == m.end()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + + std::same_as decltype(auto) i4 = m.erase(std::next(m.begin(), 1)); + assert(m.size() == 4); + assert(i4 == std::next(m.begin())); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 6); + assert(*std::next(m.begin(), 3) == 7); + + std::same_as decltype(auto) i5 = m.erase(std::next(m.cbegin(), 2)); + assert(m.size() == 3); + assert(i5 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 7); + + std::same_as decltype(auto) i6 = m.erase(std::next(m.begin(), 2)); + assert(m.size() == 2); + assert(i6 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + + std::same_as decltype(auto) i7 = m.erase(std::next(m.cbegin(), 0)); + assert(m.size() == 1); + assert(i7 == std::next(m.begin(), 0)); + assert(*m.begin() == 5); + + std::same_as decltype(auto) i8 = m.erase(m.begin()); + assert(m.size() == 0); + assert(i8 == m.begin()); + assert(i8 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp new file mode 100644 index 00000000000000..7416977844e5df --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(const_iterator first, const_iterator last); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(m.cbegin(), m.cbegin()); + assert(m.size() == 8); + assert(i1 == m.begin()); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 4); + assert(*std::next(m.begin(), 4) == 5); + assert(*std::next(m.begin(), 5) == 6); + assert(*std::next(m.begin(), 6) == 7); + assert(*std::next(m.begin(), 7) == 8); + + std::same_as decltype(auto) i2 = m.erase(m.cbegin(), std::next(m.cbegin(), 2)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 2), std::next(m.cbegin(), 6)); + assert(m.size() == 2); + assert(i3 == std::next(m.begin(), 2)); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + + std::same_as decltype(auto) i4 = m.erase(m.cbegin(), m.cend()); + assert(m.size() == 0); + assert(i4 == m.begin()); + assert(i4 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp new file mode 100644 index 00000000000000..25d4f4af19608b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(const key_type& k); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template > +void test() { + using M = std::flat_set; + + auto make = [](std::initializer_list il) { + M m; + for (int i : il) { + m.emplace(i); + } + return m; + }; + M m = make({1, 2, 3, 4, 5, 6, 7, 8}); + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(9); + assert(n == 0); + assert(m == make({1, 2, 3, 4, 5, 6, 7, 8})); + n = m.erase(4); + assert(n == 1); + assert(m == make({1, 2, 3, 5, 6, 7, 8})); + n = m.erase(1); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7, 8})); + n = m.erase(8); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7})); + n = m.erase(3); + assert(n == 1); + assert(m == make({2, 5, 6, 7})); + n = m.erase(4); + assert(n == 0); + assert(m == make({2, 5, 6, 7})); + n = m.erase(6); + assert(n == 1); + assert(m == make({2, 5, 7})); + n = m.erase(7); + assert(n == 1); + assert(m == make({2, 5})); + n = m.erase(2); + assert(n == 1); + assert(m == make({5})); + n = m.erase(5); + assert(n == 1); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test, std::greater<>>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp new file mode 100644 index 00000000000000..cbf7cac603806d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(K&& k); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanErase = requires(M m, Transparent k) { m.erase(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanErase); +static_assert(!CanErase); +static_assert(!CanErase); +static_assert(!CanErase); + +template +struct HeterogeneousKey { + explicit HeterogeneousKey(Key key, It it) : key_(key), it_(it) {} + operator It() && { return it_; } + auto operator<=>(Key key) const { return key_ <=> key; } + friend bool operator<(const HeterogeneousKey&, const HeterogeneousKey&) { + assert(false); + return false; + } + Key key_; + It it_; +}; + +template +void test_simple() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(3); // erase(K&&) [with K=int] + assert(n == 1); + assert((m == M{1, 2, 4})); + typename M::key_type lvalue = 2; + n = m.erase(lvalue); // erase(K&&) [with K=int&] + assert(n == 1); + assert((m == M{1, 4})); + const typename M::key_type const_lvalue = 1; + n = m.erase(const_lvalue); // erase(const key_type&) + assert(n == 1); + assert((m == M{4})); +} + +template +void test_transparent_comparator() { + using M = std::flat_set; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.erase(Transparent{"abc"})), typename M::size_type); + + auto n = m.erase(Transparent{"epsilon"}); + assert(n == 1); + + M expected = {"alpha", "beta", "eta", "gamma"}; + assert(m == expected); + + auto n2 = m.erase(Transparent{"aaa"}); + assert(n2 == 0); + assert(m == expected); +} + +int main(int, char**) { + test_simple>(); + test_simple>(); + test_simple>(); + test_simple>>(); + + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>>(); + + { + // P2077's HeterogeneousKey example + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.erase(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp new file mode 100644 index 00000000000000..c3bbffabb90a08 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// containers extract() &&; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanExtract = requires(T&& t) { std::forward(t).extract(); }; + +static_assert(CanExtract&&>); +static_assert(!CanExtract&>); +static_assert(!CanExtract const&>); +static_assert(!CanExtract const&&>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + M m = M({1, 2, 3}); + + std::same_as auto keys = std::move(m).extract(); + + auto expected_keys = {1, 2, 3}; + assert(std::ranges::equal(keys, expected_keys)); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // extracted object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m = M({1, 2, 3}); + std::same_as auto keys = std::move(m).extract(); + assert(keys.size() == 3); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); + } + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + auto c = std::move(m).extract(); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we try to erase the key after value emplacement failure. + // and after erasure failure, we clear the flat_set + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp new file mode 100644 index 00000000000000..c0ddadc3006987 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair insert(const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using VT = typename M::value_type; + M m; + + const VT v1(2); + std::same_as decltype(auto) r = m.insert(v1); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + + const VT v2(1); + r = m.insert(v2); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == 1); + + const VT v3(3); + r = m.insert(v3); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); + + const VT v4(3); + r = m.insert(v4); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp new file mode 100644 index 00000000000000..7381514a70eabb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; + + M m = {1,1,1,3,3,3}; + m.insert({ + 4, + 4, + 4, + 1, + 1, + 1, + 2, + 2, + 2, + }); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(*m.begin() == V(1)); + assert(*std::next(m.begin()) == V(2)); + assert(*std::next(m.begin(), 2) == V(3)); + assert(*std::next(m.begin(), 3) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp new file mode 100644 index 00000000000000..c343d53a62215a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator insert(const_iterator position, const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = typename M::iterator; + using VT = typename M::value_type; + + M m; + const VT v1(2); + std::same_as decltype(auto) r = m.insert(m.end(), v1); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + + const VT v2(1); + r = m.insert(m.end(), v2); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == 1); + + const VT v3(3); + r = m.insert(m.end(), v3); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); + + const VT v4(3); + r = m.insert(m.end(), v4); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp new file mode 100644 index 00000000000000..d20a8ef8fdd92d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + + int ar1[] = { + 2, + 2, + 2, + 1, + 1, + 1, + 3, + 3, + 3, + }; + int ar2[] = { + 4, + 4, + 4, + 1, + 1, + 1, + 0, + 0, + 0, + }; + + M m; + m.insert(cpp17_input_iterator(ar1), cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(cpp17_input_iterator(ar2), cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp new file mode 100644 index 00000000000000..84b6c7fc1d34f6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// +// iterator insert(const_iterator position, value_type&&); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "../helpers.h" +#include "test_macros.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + using R = typename M::iterator; + M m; + std::same_as decltype(auto) r = m.insert(m.end(), V(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == V(2)); + + r = m.insert(m.end(), V(1)); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == V(1)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp new file mode 100644 index 00000000000000..536307252c6405 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// void insert_range(R&& rg); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "MoveOnly.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint container-compatible-range +template +concept CanInsertRange = requires(M m, R&& r) { m.insert_range(std::forward(r)); }; + +using Set = std::flat_set; + +static_assert(CanInsertRange>); +static_assert(CanInsertRange>); +static_assert(!CanInsertRange*>>); +static_assert(!CanInsertRange*>>); + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using M = std::flat_set, KeyContainer>; + using It = forward_iterator; + M m = {10, 8, 5, 2, 1}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), It(ar + 6)}; + static_assert(std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9, 10})); + } + { + using M = std::flat_set, KeyContainer>; + using It = cpp20_input_iterator; + M m = {8, 5, 3, 2}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), sentinel_wrapper(It(ar + 6))}; + static_assert(!std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9})); + } + { + // The "uniquing" part uses the comparator, not operator==. + struct ModTen { + bool operator()(int a, int b) const { return (a % 10) < (b % 10); } + }; + using M = std::flat_set; + M m = {21, 43, 15, 37}; + int ar[] = {33, 18, 55, 18, 42}; + m.insert_range(ar); + assert((m == M{21, 42, 43, 15, 37, 18})); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // Items are forwarded correctly from the input range (P2767). + MoveOnly a[] = {3, 1, 4, 1, 5}; + std::flat_set m; + m.insert_range(a | std::views::as_rvalue); + MoveOnly expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + // The element type of the range doesn't need to be std::pair (P2767). + int pa[] = {3, 1, 4, 1, 5}; + std::deque> a(pa, pa + 5); + std::flat_set m; + m.insert_range(a); + int expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp new file mode 100644 index 00000000000000..7d95f0521eb1f6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// pair insert( value_type&& v); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + using R = std::pair; + using V = typename M::value_type; + + M m; + std::same_as decltype(auto) r = m.insert(V(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == V(2)); + + r = m.insert(V(1)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == V(1)); + + r = m.insert(V(3)); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); + + r = m.insert(V(3)); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp new file mode 100644 index 00000000000000..fa5bf86830daec --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(sorted_unique_t, initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + M m = {1, 1, 1, 3, 3, 3}; + m.insert(std::sorted_unique, {0, 1, 2, 4}); + assert(m.size() == 5); + assert(std::distance(m.begin(), m.end()) == 5); + assert(*m.begin() == V(0)); + assert(*std::next(m.begin()) == V(1)); + assert(*std::next(m.begin(), 2) == V(2)); + assert(*std::next(m.begin(), 3) == V(3)); + assert(*std::next(m.begin(), 4) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp new file mode 100644 index 00000000000000..ef7b8391cee33c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(sorted_unique_t, InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + int ar1[] = {1, 2, 3}; + + int ar2[] = {0, 2, 4}; + + M m; + m.insert(std::sorted_unique, + cpp17_input_iterator(ar1), + cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(std::sorted_unique, + cpp17_input_iterator(ar2), + cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp new file mode 100644 index 00000000000000..72d7261a182547 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -0,0 +1,169 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair insert(P&& x); +// template iterator insert(const_iterator hint, P&& x); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// Constraints: is_constructible_v is true. +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; +using Iter = Set::const_iterator; + +static_assert(CanInsert); +static_assert(CanInsert); +static_assert(!CanInsert); +static_assert(!CanInsert); + +static int expensive_comparisons = 0; +static int cheap_comparisons = 0; + +struct CompareCounter { + int i_ = 0; + CompareCounter(int i) : i_(i) {} + friend auto operator<=>(const CompareCounter& x, const CompareCounter& y) { + expensive_comparisons += 1; + return x.i_ <=> y.i_; + } + bool operator==(const CompareCounter&) const = default; + friend auto operator<=>(const CompareCounter& x, int y) { + cheap_comparisons += 1; + return x.i_ <=> y; + } +}; + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + const int expected[] = {1, 2, 3, 4, 5}; + { + // insert(P&&) + // Unlike flat_set, here we can't use key_compare to compare value_type versus P, + // so we must eagerly convert to value_type. + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, P&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // insert(value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens last + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // emplace(Args&&...) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.emplace(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // no ambiguity between insert(pos, P&&) and insert(first, last) + using M = std::flat_set; + struct Evil { + operator M::value_type() const; + operator M::const_iterator() const; + }; + std::flat_set m; + ASSERT_SAME_TYPE(decltype(m.insert(Evil())), std::pair); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); + } + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(t); + }; + test_emplace_exception_guarantee(insert_func); + } + { + auto insert_func_iter = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(m.begin(), t); + }; + test_emplace_exception_guarantee(insert_func_iter); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp new file mode 100644 index 00000000000000..49cb6eb6163c90 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void replace(container_type&& key_cont); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanReplace = requires(T t, Args&&... args) { t.replace(std::forward(args)...); }; + +using Set = std::flat_set; +static_assert(CanReplace>); +static_assert(!CanReplace&>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = M({1, 2, 3}); + KeyContainer new_keys = {7, 8}; + auto expected_keys = new_keys; + m.replace(std::move(new_keys)); + assert(m.size() == 2); + assert(std::ranges::equal(m, expected_keys)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp new file mode 100644 index 00000000000000..23a2dc85989bb7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// `check_assertion.h` requires Unix headers and regex support. +// REQUIRES: has-unix-headers +// UNSUPPORTED: no-localization +// UNSUPPORTED: no-exceptions + +// + +// void swap(flat_set& y) noexcept; +// friend void swap(flat_set& x, flat_set& y) noexcept + +// Test that std::terminate is called if any exception is thrown during swap + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../helpers.h" +#include "check_assertion.h" + +template +void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) { + { + // key swap throws + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m1, m2; + m1.emplace(1); + m1.emplace(2); + m2.emplace(3); + m2.emplace(4); + // swap is noexcept + EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); }); + } +} + +int main(int, char**) { + { + auto swap_func = [](auto& m1, auto& m2) { swap(m1, m2); }; + test_swap_exception_guarantee(swap_func); + } + + { + auto swap_func = [](auto& m1, auto& m2) { m1.swap(m2); }; + test_swap_exception_guarantee(swap_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp new file mode 100644 index 00000000000000..bc7baa67e52a59 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend void swap(flat_set& x, flat_set& y) noexcept + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptAdlSwap = requires(T t1, T t2) { + { swap(t1, t2) } noexcept; +}; + +static_assert(NoExceptAdlSwap>); + +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptAdlSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp new file mode 100644 index 00000000000000..b0b06a9499efc7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void swap(flat_set& y) noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptMemberSwap = requires(T t1, T t2) { + { t1.swap(t2) } noexcept; +}; + +static_assert(NoExceptMemberSwap>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptMemberSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp new file mode 100644 index 00000000000000..971b5e1c338dd1 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// key_compare key_comp() const; +// value_compare value_comp() const; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + { + using M = std::flat_set; + using Comp = std::less; // the default + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + { + using Comp = std::function; + using M = std::flat_set; + Comp comp = std::greater(); + M m({}, comp); + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(!kc(1, 2)); + assert(kc(2, 1)); + auto vc = m.value_comp(); + assert(!vc(1, 2)); + assert(vc(2, 1)); + } + { + using Comp = std::less<>; + using M = std::flat_set; + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + auto a = std::make_pair(1, 2); + ASSERT_SAME_TYPE(decltype(vc(a, a)), bool); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp new file mode 100644 index 00000000000000..b14da66f611301 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// bool contains(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp new file mode 100644 index 00000000000000..507560608952b0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template bool contains(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanContains = requires(M m, Transparent k) { m.contains(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanContains); +static_assert(CanContains); +static_assert(!CanContains); +static_assert(!CanContains); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.contains(Transparent{"abc"})), bool); + ASSERT_SAME_TYPE(decltype(std::as_const(m).contains(Transparent{"b"})), bool); + assert(m.contains(Transparent{"alpha"}) == true); + assert(m.contains(Transparent{"beta"}) == true); + assert(m.contains(Transparent{"epsilon"}) == true); + assert(m.contains(Transparent{"eta"}) == true); + assert(m.contains(Transparent{"gamma"}) == true); + assert(m.contains(Transparent{"al"}) == false); + assert(m.contains(Transparent{""}) == false); + assert(m.contains(Transparent{"g"}) == false); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto b = m.contains(Transparent{3}); + assert(b); + assert(transparent_used); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp new file mode 100644 index 00000000000000..478f615358b606 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type count(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using S = typename KeyContainer::size_type; + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp new file mode 100644 index 00000000000000..b591258f74399c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template size_type count(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanCount = requires(M m, Transparent k) { m.count(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanCount); +static_assert(CanCount); +static_assert(!CanCount); +static_assert(!CanCount); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.count(Transparent{"abc"})), typename M::size_type); + ASSERT_SAME_TYPE(decltype(std::as_const(m).count(Transparent{"b"})), typename M::size_type); + assert(m.count(Transparent{"alpha"}) == 1); + assert(m.count(Transparent{"beta"}) == 1); + assert(m.count(Transparent{"epsilon"}) == 1); + assert(m.count(Transparent{"eta"}) == 1); + assert(m.count(Transparent{"gamma"}) == 1); + assert(m.count(Transparent{"al"}) == 0); + assert(m.count(Transparent{""}) == 0); + assert(m.count(Transparent{"g"}) == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.count(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp new file mode 100644 index 00000000000000..a088b7fee17d2c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair equal_range(const key_type& k); +// pair equal_range(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin, begin)); + assert(m.equal_range(1) == std::pair(begin, begin + 1)); + assert(m.equal_range(2) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(3) == std::pair(begin + 2, begin + 2)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(6) == std::pair(begin + 4, begin + 4)); + assert(m.equal_range(7) == std::pair(begin + 4, begin + 4)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin() + 4, m.cbegin() + 5)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin() + 5, m.cbegin() + 5)); + } + + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin + 5, begin + 5)); + assert(m.equal_range(1) == std::pair(begin + 4, begin + 5)); + assert(m.equal_range(2) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(3) == std::pair(begin + 3, begin + 3)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(6) == std::pair(begin + 1, begin + 1)); + assert(m.equal_range(7) == std::pair(begin + 1, begin + 1)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin(), m.cbegin() + 1)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin(), m.cbegin())); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp new file mode 100644 index 00000000000000..ede5d91e19b9fd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair equal_range(const K& x); +// template pair equal_range(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanEqualRange = requires(M m, Transparent k) { m.equal_range(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanEqualRange); +static_assert(CanEqualRange); +static_assert(!CanEqualRange); +static_assert(!CanEqualRange); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + using R = std::pair; + using CR = std::pair; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.equal_range(Transparent{"abc"})), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(Transparent{"b"})), CR); + + auto test_found = [&](auto&& map, const std::string& expected_key) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(last - first == 1); + assert(*first == expected_key); + }; + + auto test_not_found = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(first == last); + assert(first - m.begin() == expected_offset); + }; + + test_found(m, "alpha"); + test_found(m, "beta"); + test_found(m, "epsilon"); + test_found(m, "eta"); + test_found(m, "gamma"); + test_found(cm, "alpha"); + test_found(cm, "beta"); + test_found(cm, "epsilon"); + test_found(cm, "eta"); + test_found(cm, "gamma"); + + test_not_found(m, "charlie", 2); + test_not_found(m, "aaa", 0); + test_not_found(m, "zzz", 5); + test_not_found(cm, "charlie", 2); + test_not_found(cm, "aaa", 0); + test_not_found(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto p = m.equal_range(Transparent{3}); + assert(p.first != p.second); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp new file mode 100644 index 00000000000000..cf0dd2d1dd831c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator find(const key_type& k); +// const_iterator find(const key_type& k) const; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.find(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(0)), typename M::const_iterator); + assert(m.find(0) == m.end()); + assert(m.find(1) == m.begin()); + assert(m.find(2) == m.begin() + 1); + assert(m.find(3) == m.end()); + assert(m.find(4) == m.begin() + 2); + assert(m.find(5) == m.begin() + 3); + assert(m.find(6) == m.end()); + assert(m.find(7) == m.end()); + assert(std::as_const(m).find(8) == m.begin() + 4); + assert(std::as_const(m).find(9) == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp new file mode 100644 index 00000000000000..730a57b0a6cb85 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator find(const K& x); +// template const_iterator find(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanFind = requires(M m, Transparent k) { m.find(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanFind); +static_assert(CanFind); +static_assert(!CanFind); +static_assert(!CanFind); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.find(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(Transparent{"b"})), typename M::const_iterator); + + auto test_find = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.find(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_find(m, "alpha", 0); + test_find(m, "beta", 1); + test_find(m, "epsilon", 2); + test_find(m, "eta", 3); + test_find(m, "gamma", 4); + test_find(m, "charlie", 5); + test_find(m, "aaa", 5); + test_find(m, "zzz", 5); + test_find(cm, "alpha", 0); + test_find(cm, "beta", 1); + test_find(cm, "epsilon", 2); + test_find(cm, "eta", 3); + test_find(cm, "gamma", 4); + test_find(cm, "charlie", 5); + test_find(cm, "aaa", 5); + test_find(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.find(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp new file mode 100644 index 00000000000000..093c32e537ed35 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator lower_bound(const key_type& k); +// const_iterator lower_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.begin()); + assert(m.lower_bound(1) == m.begin()); + assert(m.lower_bound(2) == m.begin() + 1); + assert(m.lower_bound(3) == m.begin() + 2); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 3); + assert(m.lower_bound(6) == m.begin() + 4); + assert(m.lower_bound(7) == m.begin() + 4); + assert(std::as_const(m).lower_bound(8) == m.begin() + 4); + assert(std::as_const(m).lower_bound(9) == m.end()); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.end()); + assert(m.lower_bound(1) == m.begin() + 4); + assert(m.lower_bound(2) == m.begin() + 3); + assert(m.lower_bound(3) == m.begin() + 3); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 1); + assert(m.lower_bound(6) == m.begin() + 1); + assert(m.lower_bound(7) == m.begin() + 1); + assert(std::as_const(m).lower_bound(8) == m.begin()); + assert(std::as_const(m).lower_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp new file mode 100644 index 00000000000000..18f9bc6dd32955 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator lower_bound(const K& x); +// template const_iterator lower_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanLowerBound = requires(M m, Transparent k) { m.lower_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanLowerBound); +static_assert(CanLowerBound); +static_assert(!CanLowerBound); +static_assert(!CanLowerBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_lower_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.lower_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_lower_bound(m, "abc", 0); + test_lower_bound(m, "alpha", 0); + test_lower_bound(m, "beta", 1); + test_lower_bound(m, "bets", 2); + test_lower_bound(m, "charlie", 2); + test_lower_bound(m, "echo", 2); + test_lower_bound(m, "epsilon", 2); + test_lower_bound(m, "eta", 3); + test_lower_bound(m, "gamma", 4); + test_lower_bound(m, "golf", 5); + test_lower_bound(m, "zzz", 5); + + test_lower_bound(cm, "abc", 0); + test_lower_bound(cm, "alpha", 0); + test_lower_bound(cm, "beta", 1); + test_lower_bound(cm, "bets", 2); + test_lower_bound(cm, "charlie", 2); + test_lower_bound(cm, "echo", 2); + test_lower_bound(cm, "epsilon", 2); + test_lower_bound(cm, "eta", 3); + test_lower_bound(cm, "gamma", 4); + test_lower_bound(cm, "golf", 5); + test_lower_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.lower_bound(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp new file mode 100644 index 00000000000000..ab34de85103175 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator upper_bound(const key_type& k); +// const_iterator upper_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.begin()); + assert(m.upper_bound(1) == m.begin() + 1); + assert(m.upper_bound(2) == m.begin() + 2); + assert(m.upper_bound(3) == m.begin() + 2); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 4); + assert(m.upper_bound(6) == m.begin() + 4); + assert(std::as_const(m).upper_bound(7) == m.begin() + 4); + assert(std::as_const(m).upper_bound(8) == m.end()); + assert(std::as_const(m).upper_bound(9) == m.end()); + } + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.end()); + assert(m.upper_bound(1) == m.end()); + assert(m.upper_bound(2) == m.begin() + 4); + assert(m.upper_bound(3) == m.begin() + 3); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 2); + assert(m.upper_bound(6) == m.begin() + 1); + assert(m.upper_bound(7) == m.begin() + 1); + assert(std::as_const(m).upper_bound(8) == m.begin() + 1); + assert(std::as_const(m).upper_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp new file mode 100644 index 00000000000000..69ce2ae926a305 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator upper_bound(const K& x); +// template const_iterator upper_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanUpperBound = requires(M m, Transparent k) { m.upper_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanUpperBound); +static_assert(CanUpperBound); +static_assert(!CanUpperBound); +static_assert(!CanUpperBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_upper_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.upper_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_upper_bound(m, "abc", 0); + test_upper_bound(m, "alpha", 1); + test_upper_bound(m, "beta", 2); + test_upper_bound(m, "bets", 2); + test_upper_bound(m, "charlie", 2); + test_upper_bound(m, "echo", 2); + test_upper_bound(m, "epsilon", 3); + test_upper_bound(m, "eta", 4); + test_upper_bound(m, "gamma", 5); + test_upper_bound(m, "golf", 5); + test_upper_bound(m, "zzz", 5); + + test_upper_bound(cm, "abc", 0); + test_upper_bound(cm, "alpha", 1); + test_upper_bound(cm, "beta", 2); + test_upper_bound(cm, "bets", 2); + test_upper_bound(cm, "charlie", 2); + test_upper_bound(cm, "echo", 2); + test_upper_bound(cm, "epsilon", 3); + test_upper_bound(cm, "eta", 4); + test_upper_bound(cm, "gamma", 5); + test_upper_bound(cm, "golf", 5); + test_upper_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.upper_bound(Transparent{2}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h new file mode 100644 index 00000000000000..9fff262d84234e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -0,0 +1,294 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_flat_set_HELPERS_H +#define SUPPORT_flat_set_HELPERS_H + +#include +#include +#include +#include +#include + +#include "test_allocator.h" +#include "test_macros.h" + +template +void check_invariant(const std::flat_set& m) { + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); + auto key_equal = [&](const auto& x, const auto& y) { + const auto& c = m.key_comp(); + return !c(x, y) && !c(y, x); + }; + assert(std::adjacent_find(m.begin(), m.end(), key_equal) == m.end()); +} + +struct StartsWith { + explicit StartsWith(char ch) : lower_(1, ch), upper_(1, ch + 1) {} + StartsWith(const StartsWith&) = delete; + void operator=(const StartsWith&) = delete; + struct Less { + using is_transparent = void; + bool operator()(const std::string& a, const std::string& b) const { return a < b; } + bool operator()(const StartsWith& a, const std::string& b) const { return a.upper_ <= b; } + bool operator()(const std::string& a, const StartsWith& b) const { return a < b.lower_; } + bool operator()(const StartsWith&, const StartsWith&) const { + assert(false); // should not be called + return false; + } + }; + +private: + std::string lower_; + std::string upper_; +}; + +template +struct CopyOnlyVector : std::vector { + using std::vector::vector; + + CopyOnlyVector(const CopyOnlyVector&) = default; + CopyOnlyVector(CopyOnlyVector&& other) : CopyOnlyVector(other) {} + CopyOnlyVector(CopyOnlyVector&& other, std::vector::allocator_type alloc) : CopyOnlyVector(other, alloc) {} + + CopyOnlyVector& operator=(const CopyOnlyVector&) = default; + CopyOnlyVector& operator=(CopyOnlyVector& other) { return this->operator=(other); } +}; + +template +struct Transparent { + T t; + + operator T() const + requires ConvertibleToT + { + return t; + } +}; + +template +using ConvertibleTransparent = Transparent; + +template +using NonConvertibleTransparent = Transparent; + +struct TransparentComparator { + using is_transparent = void; + + bool* transparent_used = nullptr; + TransparentComparator() = default; + TransparentComparator(bool& used) : transparent_used(&used) {} + + template + bool operator()(const T& t, const Transparent& transparent) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return t < transparent.t; + } + + template + bool operator()(const Transparent& transparent, const T& t) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return transparent.t < t; + } + + template + bool operator()(const T& t1, const T& t2) const { + return t1 < t2; + } +}; + +struct NonTransparentComparator { + template + bool operator()(const T&, const Transparent&) const; + + template + bool operator()(const Transparent&, const T&) const; + + template + bool operator()(const T&, const T&) const; +}; + +struct NoDefaultCtr { + NoDefaultCtr() = delete; +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +struct EmplaceUnsafeContainer : std::vector { + using std::vector::vector; + + template + auto emplace(Args&&... args) -> decltype(std::declval>().emplace(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } + + template + auto insert(Args&&... args) -> decltype(std::declval>().insert(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } +}; + +template +struct ThrowOnEraseContainer : std::vector { + using std::vector::vector; + + template + auto erase(Args&&... args) -> decltype(std::declval>().erase(std::forward(args)...)) { + throw 42; + } +}; + +template +struct ThrowOnMoveContainer : std::vector { + using std::vector::vector; + + ThrowOnMoveContainer(ThrowOnMoveContainer&&) { throw 42; } + + ThrowOnMoveContainer& operator=(ThrowOnMoveContainer&&) { throw 42; } +}; + +#endif + +template +void test_emplace_exception_guarantee([[maybe_unused]] F&& emplace_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using C = TransparentComparator; + { + // Throw on emplace the key, and underlying has strong exception guarantee + using KeyContainer = std::vector>; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + + test_allocator_statistics stats; + + KeyContainer a({1, 2, 3, 4}, test_allocator{&stats}); + [[maybe_unused]] auto expected_keys = a; + M m(std::sorted_unique, std::move(a)); + + stats.throw_after = 1; + try { + emplace_function(m, 0); + assert(false); + } catch (const std::bad_alloc&) { + check_invariant(m); + // In libc++, the flat_set is unchanged + LIBCPP_ASSERT(m.size() == 4); + LIBCPP_ASSERT(std::ranges::equal(m, expected_keys)); + } + } + { + // Throw on emplace the key, and underlying has no strong exception guarantee + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(!std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + KeyContainer a = {1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + emplace_function(m, 0); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, the flat_set is cleared + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} + +template +void test_insert_range_exception_guarantee([[maybe_unused]] F&& insert_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + test_allocator_statistics stats; + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + + std::vector newValues = {0, 1, 5, 6, 7, 8}; + stats.throw_after = 1; + try { + insert_function(m, newValues); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when inserting a range + LIBCPP_ASSERT(m.size() == 0); + } +#endif +} + +template +void test_erase_exception_guarantee([[maybe_unused]] F&& erase_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + { + // key erase throws + using KeyContainer = ThrowOnEraseContainer; + using M = std::flat_set; + + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + erase_function(m, 3); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when erasing + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} +class Moveable { + int int_; + double double_; + +public: + Moveable() : int_(0), double_(0) {} + Moveable(int i, double d) : int_(i), double_(d) {} + Moveable(Moveable&& x) : int_(x.int_), double_(x.double_) { + x.int_ = -1; + x.double_ = -1; + } + Moveable& operator=(Moveable&& x) { + int_ = x.int_; + x.int_ = -1; + double_ = x.double_; + x.double_ = -1; + return *this; + } + + Moveable(const Moveable&) = delete; + Moveable& operator=(const Moveable&) = delete; + bool operator==(const Moveable& x) const { return int_ == x.int_ && double_ == x.double_; } + bool operator<(const Moveable& x) const { return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_); } + + int get() const { return int_; } + bool moved() const { return int_ == -1; } +}; + +#endif // SUPPORT_flat_set_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp new file mode 100644 index 00000000000000..c4a9810016536b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Check that std::flat_set and its iterators can be instantiated with an incomplete +// type. + +#include +#include + +struct A { + using Set = std::flat_set; + int data; + Set m; + Set::iterator it; + Set::const_iterator cit; +}; + +// Implement the operator< required in order to instantiate flat_set +bool operator<(A const& L, A const& R) { return L.data < R.data; } + +int main(int, char**) { + A a; + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp new file mode 100644 index 00000000000000..f6d08bb736d300 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend bool operator==(const flat_set& x, const flat_set& y); +// friend synth-three-way-result +// operator<=>(const flat_set& x, const flat_set& y); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_comparisons.h" +#include "test_container_comparisons.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, true)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } + { + // Comparisons use value_type's native operators, not the comparator + using C = std::flat_set>; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, false)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = C(std::sorted_unique, {std::numeric_limits::quiet_NaN()}); + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + } + { + // Comparisons use value_type's native operators, not the comparator + struct StrongComp { + bool operator()(double a, double b) const { return std::strong_order(a, b) < 0; } + }; + using C = std::flat_set; + C s1 = {1}; + C s2 = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + s1 = {1, std::numeric_limits::quiet_NaN(), 1}; + s2 = {std::numeric_limits::quiet_NaN(), 1}; + assert(std::lexicographical_compare_three_way(s1.begin(), s1.end(), s2.begin(), s2.end(), std::strong_order) == + std::strong_ordering::equal); + assert(s1 != s2); + assert((s1 <=> s2) == std::partial_ordering::unordered); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp new file mode 100644 index 00000000000000..a845b2b81e89d3 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// using key_type = Key; +// using value_type = Key; +// using key_compare = Compare; +// using value_compare = Compare; +// using reference = value_type&; +// using const_reference = const value_type&; +// using size_type = typename KeyContainer::size_type; +// using difference_type = typename KeyContainer::difference_type; +// using iterator = implementation-defined; // see [container.requirements] +// using const_iterator = implementation-defined; // see [container.requirements] +// using reverse_iterator = std::reverse_iterator; +// using const_reverse_iterator = std::reverse_iterator; +// using container_type = KeyContainer; + +#include +#include +#include +#include +#include +#include +#include +#include "min_allocator.h" + +void test() { + { + using M = std::flat_set; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(requires { typename M::value_compare; }); + } + + { + struct A {}; + struct Compare { + bool operator()(const std::string&, const std::string&) const; + }; + using M = std::flat_set>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + } + { + using C = std::flat_set, std::deque>>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + // size_type is invariably size_t + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>>); + } +} >From 684124e43df490e3f39d5208641a3afb93023a6a Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 13:21:24 +0000 Subject: [PATCH 2/3] review --- libcxx/include/__flat_set/flat_set.h | 137 +++---- .../flat.set/flat.set.capacity/empty.pass.cpp | 14 +- .../flat.set.capacity/max_size.pass.cpp | 8 +- .../flat.set/flat.set.capacity/size.pass.cpp | 14 +- .../flat.set/flat.set.cons/alloc.pass.cpp | 6 +- .../assign_initializer_list.pass.cpp | 19 +- .../flat.set/flat.set.cons/compare.pass.cpp | 6 +- .../flat.set.cons/containers.pass.cpp | 25 +- .../flat.set/flat.set.cons/copy.pass.cpp | 6 +- .../flat.set.cons/copy_alloc.pass.cpp | 6 +- .../copy_assign.addressof.compile.pass.cpp | 30 -- .../flat.set.cons/copy_assign.pass.cpp | 17 +- .../flat.set/flat.set.cons/deduct.pass.cpp | 353 +++++++++--------- .../flat.set/flat.set.cons/default.pass.cpp | 36 +- .../flat.set.cons/default_noexcept.pass.cpp | 58 --- .../flat.set.cons/dtor_noexcept.pass.cpp | 6 +- .../flat.set.cons/initializer_list.pass.cpp | 6 +- .../flat.set/flat.set.cons/iter_iter.pass.cpp | 6 +- .../flat.set/flat.set.cons/move.pass.cpp | 107 +++++- .../flat.set.cons/move_alloc.pass.cpp | 10 +- .../flat.set.cons/move_assign.pass.cpp | 141 ++++++- .../flat.set.cons/move_assign_clears.pass.cpp | 101 ----- .../move_assign_noexcept.pass.cpp | 85 ----- .../flat.set.cons/move_exceptions.pass.cpp | 58 --- .../flat.set.cons/move_noexcept.pass.cpp | 94 ----- .../flat.set/flat.set.cons/pmr.pass.cpp | 6 +- .../flat.set/flat.set.cons/range.pass.cpp | 6 +- .../flat.set.cons/sorted_container.pass.cpp | 6 +- .../sorted_initializer_list.pass.cpp | 10 +- .../flat.set.cons/sorted_iter_iter.pass.cpp | 6 +- .../flat.set.erasure/erase_if.pass.cpp | 20 +- .../erase_if_exceptions.pass.cpp | 7 +- .../flat.set.iterators/iterator.pass.cpp | 18 +- .../iterator_comparison.pass.cpp | 14 +- .../reverse_iterator.pass.cpp | 8 +- .../flat.set.modifiers/clear.pass.cpp | 18 +- .../flat.set.modifiers/emplace.pass.cpp | 25 +- .../flat.set.modifiers/emplace_hint.pass.cpp | 25 +- .../flat.set.modifiers/erase_iter.pass.cpp | 25 +- .../erase_iter_iter.pass.cpp | 24 +- .../flat.set.modifiers/erase_key.pass.cpp | 37 +- .../erase_key_transparent.pass.cpp | 34 +- .../flat.set.modifiers/extract.pass.cpp | 21 +- .../flat.set.modifiers/insert_cv.pass.cpp | 33 +- .../insert_initializer_list.pass.cpp | 42 ++- .../insert_iter_cv.pass.cpp | 23 +- .../insert_iter_iter.pass.cpp | 27 +- .../insert_iter_rv.pass.cpp | 43 ++- .../flat.set.modifiers/insert_range.pass.cpp | 38 +- .../flat.set.modifiers/insert_rv.pass.cpp | 42 ++- .../insert_sorted_initializer_list.pass.cpp | 35 +- .../insert_sorted_iter_iter.pass.cpp | 29 +- .../insert_transparent.pass.cpp | 21 +- .../flat.set.modifiers/replace.pass.cpp | 50 +-- .../flat.set.modifiers/swap_free.pass.cpp | 16 +- .../flat.set.modifiers/swap_member.pass.cpp | 14 +- .../flat.set/flat.set.observers/comp.pass.cpp | 6 +- .../flat.set.operations/contains.pass.cpp | 14 +- .../contains_transparent.pass.cpp | 17 +- .../flat.set.operations/count.pass.cpp | 14 +- .../count_transparent.pass.cpp | 16 +- .../flat.set.operations/equal_range.pass.cpp | 14 +- .../equal_range_transparent.pass.cpp | 16 +- .../flat.set.operations/find.pass.cpp | 14 +- .../find_transparent.pass.cpp | 16 +- .../flat.set.operations/lower_bound.pass.cpp | 14 +- .../lower_bound_transparent.pass.cpp | 16 +- .../flat.set.operations/upper_bound.pass.cpp | 14 +- .../upper_bound_transparent.pass.cpp | 17 +- .../container.adaptors/flat.set/helpers.h | 19 +- .../flat.set/incomplete_type.pass.cpp | 5 +- .../flat.set/op_compare.pass.cpp | 17 +- 72 files changed, 1214 insertions(+), 1087 deletions(-) delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index c920632c453bf5..37e4c9f7c686b0 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP___FLAT_set_FLAT_SET_H -#define _LIBCPP___FLAT_set_FLAT_SET_H +#ifndef _LIBCPP___FLAT_SET_FLAT_SET_H +#define _LIBCPP___FLAT_SET_FLAT_SET_H #include <__algorithm/lexicographical_compare_three_way.h> #include <__algorithm/min.h> @@ -99,13 +99,6 @@ class flat_set { using const_reverse_iterator = std::reverse_iterator; using container_type = _KeyContainer; -private: - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = - uses_allocator::value; - - _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; - public: // [flat.set.cons], construct/copy/destroy _LIBCPP_HIDE_FROM_ABI @@ -178,31 +171,31 @@ class flat_set { : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( @@ -210,7 +203,7 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { @@ -219,12 +212,12 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) # if _LIBCPP_HAS_EXCEPTIONS try @@ -239,14 +232,14 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert(__first, __last); } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { @@ -254,7 +247,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { @@ -262,7 +255,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, @@ -274,37 +267,37 @@ class flat_set { } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert_range(std::forward<_Range>(__rg)); } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { insert_range(std::forward<_Range>(__rg)); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} @@ -334,11 +327,8 @@ class flat_set { // iterators _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } @@ -382,7 +372,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { return emplace(std::forward<_Kp>(__x)); } @@ -395,7 +385,7 @@ class flat_set { } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { return emplace_hint(__hint, std::forward<_Kp>(__x)); } @@ -425,7 +415,7 @@ class flat_set { __reserve(ranges::size(__range)); } - __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + __append_sort_merge_unique(std::forward<_Range>(__range)); } _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } @@ -468,7 +458,7 @@ class flat_set { } template - requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> && !is_convertible_v<_Kp &&, const_iterator>) _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { auto [__first, __last] = equal_range(__x); @@ -505,13 +495,13 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { return __find_impl(*this, __x); } @@ -519,7 +509,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { return contains(__x) ? 1 : 0; } @@ -527,7 +517,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { return find(__x) != end(); } @@ -541,13 +531,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { return ranges::lower_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { return ranges::lower_bound(__keys_, __x, __compare_); } @@ -561,13 +551,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { return ranges::upper_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { return ranges::upper_bound(__keys_, __x, __compare_); } @@ -581,12 +571,12 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { return __equal_range_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { return __equal_range_impl(*this, __x); } @@ -611,14 +601,14 @@ class flat_set { }; template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), __compare_(std::forward<_CompArg>(__comp)...) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc)), __compare_(std::forward<_CompArg>(__comp)...) {} @@ -637,17 +627,30 @@ class flat_set { __keys_.erase(__dup_start, __keys_.end()); } - template - _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { - auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); - size_type __old_size = size(); - if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { - __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + template + _LIBCPP_HIDE_FROM_ABI void __append(_InputIterator __first, _InputIterator __last) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append(_Range&& __rng) { + if constexpr (requires { __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); }) { + // C++23 Sequence Container should have insert_range member function + __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); + } else if constexpr (ranges::common_range<_Range>) { + __keys_.insert(__keys_.end(), ranges::begin(__rng), ranges::end(__rng)); } else { - for (; __first != __last; ++__first) { - __keys_.insert(__keys_.end(), *__first); + for (auto&& __x : __rng) { + __keys_.insert(__keys_.end(), std::forward(__x)); } } + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_Args&&... __args) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + __append(std::forward<_Args>(__args)...); if (size() != __old_size) { if constexpr (!_WasSorted) { ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); @@ -831,18 +834,18 @@ template struct uses_allocator, _Allocator> : bool_constant> {}; - template - _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type - erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { - auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); - auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { - return static_cast(__pred(e)); - }); - auto __res = __flat_set.__keys_.end() - __it; - __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); - __guard.__complete(); - return __res; - } +template +_LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type +erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; +} _LIBCPP_END_NAMESPACE_STD @@ -850,4 +853,4 @@ _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS -#endif // _LIBCPP___FLAT_set_FLAT_SET_H +#endif // _LIBCPP___FLAT_SET_FLAT_SET_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp index 204df1d681af1b..223b92fc3e8e84 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m; @@ -38,11 +38,15 @@ void test() { assert(m.empty()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index cd7f424e00ece2..0489d886257911 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -24,7 +24,8 @@ #include "test_allocator.h" #include "test_macros.h" -int main(int, char**) { +void test() { + { using A1 = limited_allocator; using C = std::flat_set, std::vector>; @@ -59,5 +60,10 @@ int main(int, char**) { assert(c.max_size() <= max_dist); assert(c.max_size() <= alloc_max_size(std::allocator())); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp index 7c156e95ecb1c8..9f5ffdd0663513 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; using S = typename M::size_type; { @@ -56,11 +56,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp index acc0817d7cac4d..d14e883dd5e936 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -22,7 +22,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -55,6 +55,10 @@ int main(int, char**) { auto v = std::move(m).extract(); assert(v.get_allocator().get_id() == 5); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7f75f1e1611e3b..7e948d7c5fe976 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -33,7 +33,6 @@ void test() { m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); - LIBCPP_ASSERT(std::ranges::equal(m, expected)); } { M m = {10, 8}; @@ -44,13 +43,17 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp index b3bee18f5a936b..110757a1bb9ab6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -78,6 +78,10 @@ int main(int, char**) { auto keys = std::move(m).extract(); assert(keys.get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp index 3d1e6240c952e8..6b1246885bf527 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -36,7 +36,7 @@ void conversion_test(T); template concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -116,21 +116,16 @@ int main(int, char**) { auto m = M(ks, A(4)); // replaces the allocators assert(!ks.empty()); // it was an lvalue above assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); + auto keys = M(m).extract(); assert(keys.get_allocator() == A(4)); - } - { - // flat_set(container_type , const Allocator&) + // explicit(false) - using A = test_allocator; - using M = std::flat_set, std::deque>; static_assert(ImplicitlyConstructible&, const A&>); - auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); - M m = {ks, A(4)}; // implicit ctor - assert(!ks.empty()); // it was an lvalue above - assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); - assert(keys.get_allocator() == A(4)); + M m2 = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert(m2 == m); + auto keys2 = std::move(m).extract(); + assert(keys2.get_allocator() == A(4)); } { // flat_set(container_type , key_compare, const Allocator&) @@ -153,6 +148,10 @@ int main(int, char**) { keys = std::move(m2).extract(); assert(keys.get_allocator() == A(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp index f1dbc955e1b0de..1ba550d98f01f6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -21,7 +21,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; std::vector> ks({1, 3, 5}, test_allocator(6)); @@ -59,6 +59,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == other_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp index 59fb9d0a38366f..5011bd20030641 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -23,7 +23,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -58,6 +58,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == test_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp deleted file mode 100644 index 169b469f3bca68..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp +++ /dev/null @@ -1,30 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(const flat_set& s); - -// Validate whether the container can be copy-assigned (move-assigned, swapped) -// with an ADL-hijacking operator& - -#include -#include - -#include "test_macros.h" -#include "operator_hijacker.h" - -void test() { - std::flat_set so; - std::flat_set s; - s = so; - s = std::move(so); - swap(s, so); -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp index cdd5045f4bb9f7..695363e3aeabab 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -17,11 +17,12 @@ #include #include +#include "operator_hijacker.h" #include "test_macros.h" #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // test_allocator is not propagated using C = test_less; @@ -81,5 +82,19 @@ int main(int, char**) { m = static_cast(m); assert((m == M{{1, 2}})); } + { + // Validate whether the container can be copy-assigned (move-assigned, swapped) + // with an ADL-hijacking operator& + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); + } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp index 612e64a7c42f23..607fe0d1a9713a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -26,24 +26,21 @@ #include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" -using P = std::pair; -using PC = std::pair; - void test_copy() { { - std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set source = {1, 2}; std::flat_set s(source); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s{source}; // braces instead of parens ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s(source, std::allocator()); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); @@ -52,275 +49,259 @@ void test_copy() { void test_containers() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); - std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + int expected[] = {1, 2, 3, INT_MAX}; { - std::flat_set s(ks, vs); + std::flat_set s(ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + std::flat_set s(std::sorted_unique, sorted_ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, test_allocator(0, 44)); + std::flat_set s(ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_containers_compare() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); - std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + int expected[] = {INT_MAX, 3, 2, 1}; { - std::flat_set s(ks, vs, std::greater()); + std::flat_set s(ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_iter_iter() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const int arr[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arr[] = {1, 2, 3, INT_MAX}; + const int arrc[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arrc[] = {1, 2, 3, INT_MAX}; { std::flat_set m(std::begin(arr), std::end(arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::begin(arrc), std::end(arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.begin(), mo.end()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.cbegin(), mo.cend()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); - } - { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); + // This does not deduce to flat_set(InputIterator, InputIterator) + // But deduces to flat_set(initializer_list) + int source[3] = {1, 2, 3}; + std::flat_set s = {source, source + 3}; + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 2); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + int source[3] = {1, 2, 3}; std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); assert(s.size() == 3); } } void test_iter_iter_compare() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m(std::begin(arr), std::end(arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::begin(arrc), std::end(arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set mo; - std::flat_set m(mo.begin(), mo.end(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } - { - std::flat_set mo; - std::flat_set m(mo.cbegin(), mo.cend(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } + // const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m(std::begin(arr), std::end(arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.begin(), mo.end(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.cbegin(), mo.cend(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } } void test_initializer_list() { - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - { - std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - } - { - using M = std::flat_set; - M m; - std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - assert(s[m] == m); - } + // const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + // { + // std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // } + // { + // using M = std::flat_set; + // M m; + // std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // assert(s[m] == m); + // } } void test_initializer_list_compare() { - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } } void test_from_range() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; - { - std::flat_set s(std::from_range, r); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + // { + // std::flat_set s(std::from_range, r); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } void test_from_range_compare() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; - { - std::flat_set s(std::from_range, r, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + // { + // std::flat_set s(std::from_range, r, std::greater()); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } int main(int, char**) { @@ -335,7 +316,7 @@ int main(int, char**) { test_from_range(); test_from_range_compare(); - AssociativeContainerDeductionGuidesSfinaeAway>(); + AssociativeContainerDeductionGuidesSfinaeAway>(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp index 64b0bfcb383a72..292af96c61582f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -19,9 +19,10 @@ #include #include -#include "test_macros.h" #include "min_allocator.h" +#include "MoveOnly.h" #include "test_allocator.h" +#include "test_macros.h" struct DefaultCtableComp { explicit DefaultCtableComp() { default_constructed_ = true; } @@ -29,7 +30,12 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +void test() { { std::flat_set m; assert(m.empty()); @@ -60,6 +66,32 @@ int main(int, char**) { assert(m.key_comp().default_constructed_); } } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp deleted file mode 100644 index b4a3b6de205a31..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set() -// noexcept( -// is_nothrow_default_constructible_v && -// is_nothrow_default_constructible_v); - -// This tests a conforming extension - -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -struct ThrowingCtorComp { - ThrowingCtorComp() noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -int main(int, char**) { -#if defined(_LIBCPP_VERSION) - { - using C = std::flat_set; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set, std::vector>>; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } -#endif // _LIBCPP_VERSION - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp index c0d315c0ce74b4..fa1e2478af4599 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -27,7 +27,7 @@ struct ThrowingDtorComp { ~ThrowingDtorComp() noexcept(false) {} }; -int main(int, char**) { +void test() { { using C = std::flat_set; static_assert(std::is_nothrow_destructible_v); @@ -52,6 +52,10 @@ int main(int, char**) { C c; } #endif // _LIBCPP_VERSION +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp index cd2319e91f760d..9aed5c88ee7268 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -35,7 +35,7 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -146,6 +146,10 @@ int main(int, char**) { M m({5, 2, 2, 3, 1, 3}, {}, a); assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp index 65eebc21a66c4c..2d0b07c9155fdb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -29,7 +29,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -131,6 +131,10 @@ int main(int, char**) { LIBCPP_ASSERT(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp index 69b340ad09fe15..b2853844b986c6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -25,7 +25,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; using A = test_allocator; @@ -79,5 +79,110 @@ int main(int, char**) { LIBCPP_ASSERT(m1.empty()); LIBCPP_ASSERT(m1.size() == 0); } +} + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +void test_move_noexcept() { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +} + +#if !defined(TEST_HAS_NO_EXCEPTIONS) +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +void test_move_exception() { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } +} +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + +int main(int, char**) { + test(); + test_move_noexcept(); +#if !defined(TEST_HAS_NO_EXCEPTIONS) + test_move_exception(); +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp index fc7f68d8c967ad..489b6ff36324b3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -53,7 +53,7 @@ int main(int, char**) { assert(m.size() == 3); auto keys = std::move(m).extract(); assert(keys.get_allocator() == A(3)); - assert(std::ranges::equal(keys, expected )); + assert(std::ranges::equal(keys, expected)); // The original flat_set is moved-from. assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); @@ -63,13 +63,17 @@ int main(int, char**) { } { // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, CopyOnlyVector>; + using M = std::flat_set, CopyOnlyVector>; M m1 = M({1, 2, 3}); M m2(std::move(m1), std::allocator{}); assert(m2.size() == 3); check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index b16dc38dd40285..e55a0516ed1bed 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -22,11 +22,144 @@ #include "test_macros.h" #include "MoveOnly.h" +#include "../helpers.h" #include "../../../test_compare.h" #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +void test_move_assign_clears() { + // Preserves the class invariant for the moved-from flat_set. + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } +} + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +void test_move_assign_no_except() { + // This tests a conforming extension + + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } +} + +void test() { { using C = test_less; using A1 = test_allocator; @@ -64,6 +197,12 @@ int main(int, char**) { assert(ks.get_allocator() == A()); assert(mo.empty()); } +} + +int main(int, char**) { + test(); + test_move_assign_clears(); + test_move_assign_no_except(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp deleted file mode 100644 index 50817f4be8a812..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&&); -// Preserves the class invariant for the moved-from flat_set. - -#include -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -struct MoveNegates { - int value_ = 0; - MoveNegates() = default; - MoveNegates(int v) : value_(v) {} - MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } - MoveNegates& operator=(MoveNegates&& rhs) { - value_ = rhs.value_; - rhs.value_ = -rhs.value_; - return *this; - } - ~MoveNegates() = default; - auto operator<=>(const MoveNegates&) const = default; -}; - -struct MoveClears { - int value_ = 0; - MoveClears() = default; - MoveClears(int v) : value_(v) {} - MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } - MoveClears& operator=(MoveClears&& rhs) { - value_ = rhs.value_; - rhs.value_ = 0; - return *this; - } - ~MoveClears() = default; - auto operator<=>(const MoveClears&) const = default; -}; - -int main(int, char**) { - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, std::vector>; - M m1 = M({1, 2, 3}); - M m2 = M({1, 2}); - m2 = std::move(m1); - assert(m2.size() == 3); - check_invariant(m1); - LIBCPP_ASSERT(m1.empty()); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp deleted file mode 100644 index 86f3568f0d67a6..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&& c) -// noexcept( -// is_nothrow_move_assignable::value && -// is_nothrow_move_assignable::value && -// is_nothrow_copy_assignable::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include - -#include "MoveOnly.h" -#include "test_allocator.h" -#include "test_macros.h" - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -struct MoveThrowsComp { - MoveThrowsComp(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp(const MoveThrowsComp&) noexcept(true); - MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); - bool operator()(const auto&, const auto&) const; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - // Test with a comparator that throws on move-assignment. - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); - } - { - // Test with a container that throws on move-assignment. - using C = std::flat_set, std::pmr::vector>; - static_assert(!std::is_nothrow_move_assignable_v); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp deleted file mode 100644 index 17e4e40387606c..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 -// UNSUPPORTED: no-exceptions - -// - -// flat_set(flat_set&& s); -// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. - -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -static int countdown = 0; - -struct EvilContainer : std::vector { - EvilContainer() = default; - EvilContainer(EvilContainer&& rhs) { - // Throw on move-construction. - if (--countdown == 0) { - rhs.insert(rhs.end(), 0); - rhs.insert(rhs.end(), 0); - throw 42; - } - } -}; - -int main(int, char**) { - { - using M = std::flat_set, EvilContainer>; - M mo = {1, 2, 3}; - countdown = 1; - try { - M m = std::move(mo); - assert(false); // not reached - } catch (int x) { - assert(x == 42); - } - // The source flat_set maintains its class invariant. - check_invariant(mo); - LIBCPP_ASSERT(mo.empty()); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp deleted file mode 100644 index 49d1151fd8a993..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set(flat_set&&) -// noexcept(is_nothrow_move_constructible::value && -// is_nothrow_move_constructible::value && -// is_nothrow_copy_constructible::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -template -struct ThrowingMoveAllocator { - using value_type = T; - explicit ThrowingMoveAllocator() = default; - ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; - ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} - T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } - void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } - friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; -}; - -struct ThrowingMoveComp { - ThrowingMoveComp() = default; - ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} - ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - { - using C = std::flat_set, std::deque>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#if _LIBCPP_VERSION - { - // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators - using C = std::flat_set, std::deque>>; - static_assert(!std::is_nothrow_move_constructible_v>>); - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#endif // _LIBCPP_VERSION - { - // Comparator fails to be nothrow-move-constructible - using C = std::flat_set; - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp index 785718d2eed333..1a4eafa8802918 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -28,7 +28,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // flat_set(const Allocator& a); using M = std::flat_set, std::pmr::vector>; @@ -317,6 +317,10 @@ int main(int, char**) { assert(vm[0].key_comp() == C(4)); assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp index bb9f99c228bfec..bd7b5c12432e96 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -56,7 +56,7 @@ static_assert( !std:: is_constructible_v>, std::less, std::allocator>); -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -168,6 +168,10 @@ int main(int, char**) { assert(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp index 2d442d49667bd0..873ff32b62936a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -138,6 +138,10 @@ int main(int, char**) { assert(m2 == m); assert(std::move(m2).extract().get_allocator() == A(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp index 01956a78c7f48d..a8dac35aefee81 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -33,10 +33,10 @@ template std::initializer_list il = {1, 2, 4, 5}; -const auto il1 = il; -const auto il2 = il; +void test() { + const auto il1 = il; + const auto il2 = il; -int main(int, char**) { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -145,6 +145,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp index b5229a84dd5133..b184ee9c3f5aba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -28,7 +28,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -151,6 +151,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp index 134db83aef3cad..806779bc7d16bc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -49,7 +49,7 @@ void test0( } template -void test() { +void test_one() { // Test all the plausible signatures for this predicate. auto is1 = [](typename S::const_reference v) { return v == 1; }; auto is2 = [](typename S::value_type v) { return v == 2; }; @@ -76,14 +76,18 @@ void test() { test0({1, 2, 3}, False, {1, 2, 3}, 0); } +void test() { + test_one>(); + test_one, std::vector>>>(); + test_one, std::vector>>>(); + test_one, std::deque>>>(); + test_one, std::deque>>>(); + test_one>(); + test_one>(); +} + int main(int, char**) { - test>(); - test, std::vector>>>(); - test, std::vector>>>(); - test, std::deque>>>(); - test, std::deque>>>(); - test>(); - test>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp index 6bbe1ad4f01670..37b4a40f0165cf 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -65,7 +65,7 @@ struct ErasurePredicate { bool operator()(const auto& x) const { return (3 <= x && x <= 5); } }; -int main(int, char**) { +void test() { const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; { using M = std::flat_set; @@ -124,5 +124,10 @@ int main(int, char**) { } } } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp index c07297a141ad10..846bcff63d7736 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -30,7 +30,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -67,15 +67,15 @@ void test() { assert(i == m.begin()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::iterator ii1{}, ii2{}; C::iterator ii4 = ii1; C::const_iterator cii{}; @@ -88,6 +88,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp index 29441dcc57d40e..3027cdd4076eea 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using KI = typename KeyContainer::iterator; @@ -144,11 +144,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp index a16383cdcf5383..d1e4cef3de19e8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include -int main(int, char**) { +void test() { { using M = std::flat_set, std::deque>; M m = {1, 2, 3, 4}; @@ -69,7 +69,7 @@ int main(int, char**) { } { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::reverse_iterator ii1{}, ii2{}; C::reverse_iterator ii4 = ii1; C::const_reverse_iterator cii{}; @@ -82,6 +82,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp index 221a13fa057577..efa13a51c30bb3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -38,7 +38,7 @@ static_assert(NoExceptClear, ThrowOnMoveContai #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -50,13 +50,17 @@ void test() { assert(m.size() == 0); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp index 95f7a3c5f5d34a..79800e894afbfc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -28,7 +28,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -121,21 +121,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp index de855d5e5c3009..b3bd8adf0c35d8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -27,7 +27,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = M::iterator; @@ -134,21 +134,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp index 386af04d26e9a2..42562b84b4e22d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -27,7 +27,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -106,16 +106,21 @@ void test() { assert(i8 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp index 7416977844e5df..d402a7ba0285ec 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -77,15 +77,21 @@ void test() { assert(i4 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp index 25d4f4af19608b..d81422d3871876 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template > -void test() { +void test_one() { using M = std::flat_set; auto make = [](std::initializer_list il) { @@ -70,22 +70,27 @@ void test() { assert(m.empty()); } -int main(int, char**) { - test>(); - test, std::greater<>>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one, std::greater<>>(); + test_one>(); + test_one>(); + test_one>>(); +} - { - auto erase_function = [](auto& m, auto key_arg) { - using Map = std::decay_t; - using Key = typename Map::key_type; - const Key key{key_arg}; - m.erase(key); - }; - test_erase_exception_guarantee(erase_function); - } +void test_exception() { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp index cbf7cac603806d..c383844eb4973e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -50,7 +50,7 @@ struct HeterogeneousKey { }; template -void test_simple() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -86,11 +86,11 @@ void test_transparent_comparator() { assert(m == expected); } -int main(int, char**) { - test_simple>(); - test_simple>(); - test_simple>(); - test_simple>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_transparent_comparator>(); test_transparent_comparator>(); @@ -129,14 +129,20 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } - { - auto erase_transparent = [](auto& m, auto key_arg) { - using Set = std::decay_t; - using Key = typename Set::key_type; - m.erase(Transparent{key_arg}); - }; - test_erase_exception_guarantee(erase_transparent); - } +} + +void test_exception() { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp index c3bbffabb90a08..dfa21a807f0254 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -33,7 +33,7 @@ static_assert(!CanExtract const&>); static_assert(!CanExtract const&&>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; M m = M({1, 2, 3}); @@ -45,11 +45,12 @@ void test() { LIBCPP_ASSERT(m.empty()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { // extracted object maintains invariant if the underlying container does not clear after move using M = std::flat_set, CopyOnlyVector>; @@ -59,7 +60,9 @@ int main(int, char**) { check_invariant(m); LIBCPP_ASSERT(m.empty()); } +} +void test_exception() { { #ifndef TEST_HAS_NO_EXCEPTIONS using KeyContainer = ThrowOnMoveContainer; @@ -79,5 +82,11 @@ int main(int, char**) { } #endif } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp index c0ddadc3006987..e0cb80f74462cd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -59,20 +59,25 @@ void test() { assert(*r.first == 3); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using value_type = typename std::decay_t::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(p); - }; - test_emplace_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp index 7381514a70eabb..bf94fd9f5b11fd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -23,12 +23,12 @@ #include "min_allocator.h" template -void test() { - using Key = typename KeyContainer::value_type; - using M = std::flat_set, KeyContainer>; - using V = typename M::value_type; +void test_one() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; - M m = {1,1,1,3,3,3}; + M m = {1, 1, 1, 3, 3, 3}; m.insert({ 4, 4, @@ -48,20 +48,26 @@ void test() { assert(*std::next(m.begin(), 3) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(il); - }; - test_insert_range_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index c343d53a62215a..d6791853e0debd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = typename M::iterator; @@ -55,13 +55,15 @@ void test() { assert(*r == 3); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; using value_type = typename FlatSet::value_type; @@ -69,6 +71,11 @@ int main(int, char**) { m.insert(m.begin(), p); }; test_emplace_exception_guarantee(insert_func); - } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp index d20a8ef8fdd92d..8063686c960ed3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; int ar1[] = { @@ -73,15 +73,22 @@ void test() { M expected2{0, 1, 2, 3, 4}; assert(m == expected2); } + +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp index 84b6c7fc1d34f6..d29de98e4d3ddb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -22,7 +22,7 @@ #include "test_macros.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -49,25 +49,30 @@ void test() { assert(*r == V(3)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(m.begin(), std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp index 536307252c6405..ed33827a7355c9 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -39,7 +39,7 @@ static_assert(!CanInsertRange*>>) static_assert(!CanInsertRange*>>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -75,31 +75,29 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { - // Items are forwarded correctly from the input range (P2767). + // Items are forwarded correctly from the input range. MoveOnly a[] = {3, 1, 4, 1, 5}; std::flat_set m; m.insert_range(a | std::views::as_rvalue); MoveOnly expected[] = {1, 3, 4, 5}; assert(std::ranges::equal(m, expected)); } - { - // The element type of the range doesn't need to be std::pair (P2767). - int pa[] = {3, 1, 4, 1, 5}; - std::deque> a(pa, pa + 5); - std::flat_set m; - m.insert_range(a); - int expected[] = {1, 3, 4, 5}; - assert(std::ranges::equal(m, expected)); - } - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; - test_insert_range_exception_guarantee(insert_func); - } +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp index 7d95f0521eb1f6..faf74142caff5c 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -25,7 +25,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; using R = std::pair; @@ -57,24 +57,30 @@ void test() { assert(*r.first == V(3)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp index fa5bf86830daec..38c36d1befaa7c 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -38,21 +38,26 @@ void test() { assert(*std::next(m.begin(), 4) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(std::sorted_unique, il); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp index ef7b8391cee33c..6258c4dbfdcbba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -60,18 +60,23 @@ void test() { assert(m == expected2); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - m.insert(std::sorted_unique, newValues.begin(), newValues.end()); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp index 72d7261a182547..d2ddf95aac2bb7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -57,7 +57,7 @@ struct CompareCounter { }; template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -121,11 +121,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // no ambiguity between insert(pos, P&&) and insert(first, last) @@ -139,6 +139,9 @@ int main(int, char**) { ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); } +} + +void test_exception() { { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; @@ -165,5 +168,11 @@ int main(int, char**) { }; test_emplace_exception_guarantee(insert_func_iter); } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp index 49cb6eb6163c90..fca33bd41449e0 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -31,7 +31,7 @@ static_assert(CanReplace>); static_assert(!CanReplace&>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -43,30 +43,36 @@ void test() { assert(std::ranges::equal(m, expected_keys)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { #ifndef TEST_HAS_NO_EXCEPTIONS - using KeyContainer = ThrowOnMoveContainer; - using M = std::flat_set; + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; - M m; - m.emplace(1); - m.emplace(2); - try { - KeyContainer new_keys{3, 4}; - m.replace(std::move(new_keys)); - assert(false); - } catch (int) { - check_invariant(m); - // In libc++, we clear the map - LIBCPP_ASSERT(m.size() == 0); - } -#endif + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); } +#endif +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp index bc7baa67e52a59..ed13ba1ef3fea7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -24,6 +24,8 @@ #include "test_macros.h" #include "../helpers.h" +#include "check_assertion.h" + // test noexcept template @@ -38,7 +40,7 @@ static_assert(NoExceptAdlSwap, ThrowOnMoveCont #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -84,11 +86,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp index b0b06a9499efc7..1eac55d768ce0b 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -37,7 +37,7 @@ static_assert(NoExceptMemberSwap, ThrowOnMoveC #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -82,11 +82,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp index 971b5e1c338dd1..ba2c428c9e30e2 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -21,7 +21,7 @@ #include "test_macros.h" -int main(int, char**) { +void test() { { using M = std::flat_set; using Comp = std::less; // the default @@ -67,6 +67,10 @@ int main(int, char**) { assert(vc(1, 2)); assert(!vc(2, 1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp index b14da66f611301..e23683f6f28945 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp index 507560608952b0..0cdff44d11274f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanContains); static_assert(!CanContains); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.contains(Transparent{"g"}) == false); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,5 +66,10 @@ int main(int, char**) { assert(b); assert(transparent_used); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp index 478f615358b606..017f0fed3e9816 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using S = typename KeyContainer::size_type; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp index b591258f74399c..0c5ce9d5799651 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanCount); static_assert(!CanCount); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.count(Transparent{"g"}) == 0); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,6 +66,10 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp index a088b7fee17d2c..b55cbe2ac42a00 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -67,11 +67,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp index ede5d91e19b9fd..97c4af19eaef37 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanEqualRange); static_assert(!CanEqualRange); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -77,11 +77,11 @@ void test() { test_not_found(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -92,6 +92,10 @@ int main(int, char**) { assert(p.first != p.second); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp index cf0dd2d1dd831c..9ee8f043e1d9cd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -25,7 +25,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m = {1, 2, 4, 5, 8}; @@ -43,11 +43,15 @@ void test() { assert(std::as_const(m).find(9) == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp index 730a57b0a6cb85..cc8ea12bcf4a6a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanFind); static_assert(!CanFind); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -68,11 +68,11 @@ void test() { test_find(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -83,6 +83,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp index 093c32e537ed35..1ceddb2f1c9d26 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -60,11 +60,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp index 18f9bc6dd32955..19991ca05fbc8a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanLowerBound); static_assert(!CanLowerBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,11 @@ void test() { test_lower_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -89,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp index ab34de85103175..f25896e1229397 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -61,11 +61,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp index 69ce2ae926a305..c9b519d2032193 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanUpperBound); static_assert(!CanUpperBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,12 @@ void test() { test_upper_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { bool transparent_used = false; TransparentComparator c(transparent_used); @@ -88,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h index 9fff262d84234e..2ee8b021337a06 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SUPPORT_flat_set_HELPERS_H -#define SUPPORT_flat_set_HELPERS_H +#ifndef SUPPORT_FLAT_SET_HELPERS_H +#define SUPPORT_FLAT_SET_HELPERS_H #include #include @@ -149,6 +149,19 @@ struct EmplaceUnsafeContainer : std::vector { throw 42; } + + template + auto insert_range(Args&&... args) + -> decltype(std::declval>().insert_range(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } }; template @@ -291,4 +304,4 @@ class Moveable { bool moved() const { return int_ == -1; } }; -#endif // SUPPORT_flat_set_HELPERS_H +#endif // SUPPORT_FLAT_SET_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp index c4a9810016536b..faf746861df309 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -27,7 +27,10 @@ struct A { // Implement the operator< required in order to instantiate flat_set bool operator<(A const& L, A const& R) { return L.data < R.data; } +void test() { A a; } + int main(int, char**) { - A a; + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp index f6d08bb736d300..3e7aecee77fdd8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -31,7 +31,7 @@ #include "test_container_comparisons.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -69,11 +69,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { using C = std::flat_set; @@ -101,5 +101,10 @@ int main(int, char**) { assert(s1 != s2); assert((s1 <=> s2) == std::partial_ordering::unordered); } +} + +int main(int, char**) { + test(); + return 0; } >From 2e2adaf901c704be809a2b7eac60c26098fa6aa8 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 14:08:01 +0000 Subject: [PATCH 3/3] review --- .../flat.set/assert.sorted_unique.pass.cpp | 226 ++++++++++++++++++ .../assign_initializer_list.pass.cpp | 6 +- .../flat.set.cons/move_assign.pass.cpp | 67 ++++-- 3 files changed, 280 insertions(+), 19 deletions(-) create mode 100644 libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp diff --git a/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp new file mode 100644 index 00000000000000..62903af7f4e477 --- /dev/null +++ b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp @@ -0,0 +1,226 @@ +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: libcpp-hardening-mode=none +// REQUIRES: libcpp-hardening-mode=debug +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// + +// flat_set(container_type , const key_compare& __comp = key_compare()) +// flat_set(const container_type& , const _Allocator& ) +// flat_set(const container_type& , const key_compare&, const _Allocator& ) +// void replace(container_type&& ) +// + +#include +#include +#include +#include +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + using M = std::flat_set; + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{1, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{2, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7e948d7c5fe976..ad49b621490366 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -30,14 +30,16 @@ void test_one() { { M m = {8, 10}; assert(m.size() == 2); - m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + std::same_as decltype(auto) r = m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + assert(&r == &m); int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); } { M m = {10, 8}; assert(m.size() == 2); - m = {3}; + std::same_as decltype(auto) r = m = {3}; + assert(&r == &m); int expected[] = {3}; assert(std::ranges::equal(m, expected)); } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index e55a0516ed1bed..0e0ab0aa135f9f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -55,6 +55,19 @@ struct MoveClears { auto operator<=>(const MoveClears&) const = default; }; +#if !defined(TEST_HAS_NO_EXCEPTIONS) +struct MoveAssignThrows : std::vector { + using std::vector::vector; + MoveAssignThrows& operator=(MoveAssignThrows&& other) { + push_back(0); + push_back(0); + other.push_back(0); + other.push_back(0); + throw 42; + } +}; +#endif // TEST_HAS_NO_EXCEPTIONS + void test_move_assign_clears() { // Preserves the class invariant for the moved-from flat_set. { @@ -101,6 +114,23 @@ void test_move_assign_clears() { check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +#if !defined(TEST_HAS_NO_EXCEPTIONS) + { + using M = std::flat_set, MoveAssignThrows>; + M m1 = {1, 2, 3}; + M m2 = {1, 2}; + try { + m2 = std::move(m1); + assert(false); + } catch (int e) { + assert(e == 42); + } + check_invariant(m1); + check_invariant(m2); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m2.empty()); + } +#endif // TEST_HAS_NO_EXCEPTIONS } struct MoveSensitiveComp { @@ -161,12 +191,13 @@ void test_move_assign_no_except() { void test() { { - using C = test_less; - using A1 = test_allocator; - using M = std::flat_set>; - M mo = M({1, 2, 3}, C(5), A1(7)); - M m = M({}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{1, 2, 3})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -174,12 +205,13 @@ void test() { assert(mo.empty()); } { - using C = test_less; - using A1 = other_allocator; - using M = std::flat_set>; - M mo = M({4, 5}, C(5), A1(7)); - M m = M({1, 2, 3, 4}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{4, 5})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -187,11 +219,12 @@ void test() { assert(mo.empty()); } { - using A = min_allocator; - using M = std::flat_set, std::vector>; - M mo = M({5, 4, 3}, A()); - M m = M({4, 3, 2, 1}, A()); - m = std::move(mo); + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{5, 4, 3})); auto ks = std::move(m).extract(); assert(ks.get_allocator() == A()); From libcxx-commits at lists.llvm.org Sun Feb 2 06:55:10 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 06:55:10 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Implement P2897R7 aligned_accessor: An mdspan accessor expressing pointer over-alignment (PR #122603) In-Reply-To: Message-ID: <679f874e.170a0220.250938.241e@mx.google.com> ================ @@ -0,0 +1,34 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_IS_SUFFICIENTLY_ALIGNED_H +#define _LIBCPP___MEMORY_IS_SUFFICIENTLY_ALIGNED_H + +#include <__config> +#include <__cstddef/size_t.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 26 + +template ---------------- philnik777 wrote: I don't think they're just related as "alignment stuff". `is_sufficiently_aligned` is the precondition for `assume_aligned`. If `is_sufficiently_aligned` wasn't (IMO unnecessarily) non-`constexpr` I'd be strongly in favor of checking the precondition that way. https://github.com/llvm/llvm-project/pull/122603 From libcxx-commits at lists.llvm.org Sun Feb 2 08:15:00 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 08:15:00 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Speed up vector copy/move-ctors [1/3] (PR #120132) In-Reply-To: Message-ID: <679f9a04.050a0220.76f9c.49ad@mx.google.com> https://github.com/philnik777 requested changes to this pull request. > LGTM with comments applied. I would also like @philnik777 to take another look. > > Personally, I find the code a lot easier to read after this PR. We call `std::copy` directly, which everyone knows well, and we set the size explicitly from the constructor. That removes the need for calling `__construct_at_end`, which has a strange contract like that of only being called when the vector is empty. What strange contract are you talking about? AFAICT the only precondition is that there is enough space to construct the elements. I don't really care whether we call `__construct_at_end` or use `std::copy` directly, but I still find `std::copy(__v.begin(), __v.end(), begin())` _much_ more readable than the current proposal. If the only reason for this PR is readability I don't see how the current proposal is any better than the status quo. https://github.com/llvm/llvm-project/pull/120132 From libcxx-commits at lists.llvm.org Sun Feb 2 08:50:05 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 08:50:05 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <679fa23d.050a0220.e36c7.62e0@mx.google.com> https://github.com/philnik777 edited https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Sun Feb 2 08:50:05 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 08:50:05 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <679fa23d.630a0220.3ae6e7.32e1@mx.google.com> https://github.com/philnik777 commented: > Did you benchmark what to overhead for the types are? I'm not sure what you're trying to ask. https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Sun Feb 2 08:50:05 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 08:50:05 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <679fa23d.170a0220.1d6c5a.25f9@mx.google.com> ================ @@ -447,10 +449,41 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) { } # endif +template ---------------- philnik777 wrote: I'm not quite sure what kind of documentation you're asking for. Do you want a comment listing the folds it can do? > Does the code optimize `std::format("{}", 42)`? Not currently. I plan to add more folds though. https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Sun Feb 2 08:50:06 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 08:50:06 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <679fa23e.170a0220.1bd169.1e3a@mx.google.com> ================ @@ -447,10 +449,41 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) { } # endif +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional> __try_constant_folding_format( + basic_string_view<_CharT> __fmt, + basic_format_args>, _CharT>> __args) { + // [[gnu::pure]] is added to ensure that the compiler always knows that this call can be eliminated. + if (bool __is_identity = + [&] [[__gnu__::__pure__]] { return std::ranges::find_first_of(__fmt, array{'{', '}'}) == __fmt.end(); }(); ---------------- philnik777 wrote: Is there a reason for one over the other? https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Sun Feb 2 08:58:14 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Sun, 02 Feb 2025 08:58:14 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Speed up vector copy/move-ctors [1/3] (PR #120132) In-Reply-To: Message-ID: <679fa426.170a0220.2328d1.2e37@mx.google.com> winner245 wrote: > > LGTM with comments applied. I would also like @philnik777 to take another look. > > > >Personally, I find the code a lot easier to read after this PR. We call `std::copy` directly, which everyone knows well, and we set the size explicitly from the constructor. That removes the need for calling `__construct_at_end`, which has a strange contract like that of only being called when the vector is empty. > >What strange contract are you talking about? AFAICT the only precondition is that there is enough space to construct the elements. Before my patch #119632, `__construct_at_end(,,__n)` had a documented precondition of `__n > 0`, alongside an undocumented precondition of `size() > 0`. After applying #119632, we simplified this into a single precondition `size() + __n <= capacity()`. > I don't really care whether we call `__construct_at_end` or use `std::copy` directly, but I still find `std::copy(__v.begin(), __v.end(), begin())` _much_ more readable than the current proposal. If the only reason for this PR is readability I don't see how the current proposal is any better than the status quo. Please note that we are not comparing `std::copy(__v.begin(), __v.end(), begin())` with `std::copy(__v.__begin_, __v.__begin_ + __external_cap_to_internal(__v.size()), __begin_);`, but rather ```cpp __construct_at_end(__v.begin(), __v.end(), __v.size()); ``` with ```cpp std::copy(__v.__begin_, __v.__begin_ + __external_cap_to_internal(__v.size()), __begin_); __size_ = __v.size(); ``` I have no idea what `__construct_at_end` does without delving into its implementation, which has a contract and multiple lines of code that invoke specialized versions of `std::__copy`. To fully understand what `__construct_at_end` does, one has to figure out a lot more internal implementation details such as `__bit_iterator`, `__bit_reference`, and the optimized algorithms of `std::__copy` for `__bit_iterator`. In contrast, with this PR, one only needs to know the general purpose standard-form `std::copy`, which every C++ programmer is familiar with. https://github.com/llvm/llvm-project/pull/120132 From libcxx-commits at lists.llvm.org Sun Feb 2 09:00:02 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Sun, 02 Feb 2025 09:00:02 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] implement std::flat_set (PR #125241) In-Reply-To: Message-ID: <679fa492.170a0220.133bbd.66f6@mx.google.com> https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/125241 >From f315d757119fde3cf298c18914a33e9cf76f27d1 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Fri, 31 Jan 2025 15:53:09 +0000 Subject: [PATCH 1/5] [libc++] implement std::flat_set --- libcxx/include/CMakeLists.txt | 2 + libcxx/include/__flat_set/flat_set.h | 853 ++++++++++++++++++ libcxx/include/flat_set | 59 ++ libcxx/include/module.modulemap | 11 + .../flat.set/flat.set.capacity/empty.pass.cpp | 48 + .../flat.set.capacity/empty.verify.cpp | 20 + .../flat.set.capacity/max_size.pass.cpp | 63 ++ .../flat.set/flat.set.capacity/size.pass.cpp | 66 ++ .../flat.set/flat.set.cons/alloc.pass.cpp | 60 ++ .../assign_initializer_list.pass.cpp | 56 ++ .../flat.set/flat.set.cons/compare.pass.cpp | 83 ++ .../flat.set.cons/containers.pass.cpp | 158 ++++ .../flat.set/flat.set.cons/copy.pass.cpp | 64 ++ .../flat.set.cons/copy_alloc.pass.cpp | 63 ++ .../copy_assign.addressof.compile.pass.cpp | 30 + .../flat.set.cons/copy_assign.pass.cpp | 85 ++ .../flat.set.cons/deduct.compile.pass.cpp | 49 + .../flat.set/flat.set.cons/deduct.pass.cpp | 341 +++++++ .../flat.set.cons/deduct_pmr.pass.cpp | 94 ++ .../flat.set/flat.set.cons/default.pass.cpp | 65 ++ .../flat.set.cons/default_noexcept.pass.cpp | 58 ++ .../flat.set.cons/dtor_noexcept.pass.cpp | 57 ++ .../flat.set.cons/initializer_list.pass.cpp | 151 ++++ .../flat.set/flat.set.cons/iter_iter.pass.cpp | 136 +++ .../flat.set/flat.set.cons/move.pass.cpp | 83 ++ .../flat.set.cons/move_alloc.pass.cpp | 75 ++ .../flat.set.cons/move_assign.pass.cpp | 69 ++ .../flat.set.cons/move_assign_clears.pass.cpp | 101 +++ .../move_assign_noexcept.pass.cpp | 85 ++ .../flat.set.cons/move_exceptions.pass.cpp | 58 ++ .../flat.set.cons/move_noexcept.pass.cpp | 94 ++ .../flat.set/flat.set.cons/pmr.pass.cpp | 322 +++++++ .../flat.set/flat.set.cons/range.pass.cpp | 173 ++++ .../flat.set.cons/sorted_container.pass.cpp | 143 +++ .../sorted_initializer_list.pass.cpp | 150 +++ .../flat.set.cons/sorted_iter_iter.pass.cpp | 156 ++++ .../flat.set.erasure/erase_if.pass.cpp | 89 ++ .../erase_if_exceptions.pass.cpp | 128 +++ .../flat.set.iterators/iterator.pass.cpp | 93 ++ .../iterator_comparison.pass.cpp | 154 ++++ ...rator_concept_conformance.compile.pass.cpp | 77 ++ ...range_concept_conformance.compile.pass.cpp | 52 ++ .../reverse_iterator.pass.cpp | 87 ++ .../flat.set.modifiers/clear.pass.cpp | 62 ++ .../flat.set.modifiers/emplace.pass.cpp | 141 +++ .../flat.set.modifiers/emplace_hint.pass.cpp | 154 ++++ .../flat.set.modifiers/erase_iter.pass.cpp | 121 +++ .../erase_iter_iter.pass.cpp | 91 ++ .../flat.set.modifiers/erase_key.pass.cpp | 91 ++ .../erase_key_transparent.pass.cpp | 142 +++ .../flat.set.modifiers/extract.pass.cpp | 83 ++ .../flat.set.modifiers/insert_cv.pass.cpp | 78 ++ .../insert_initializer_list.pass.cpp | 67 ++ .../insert_iter_cv.pass.cpp | 74 ++ .../insert_iter_iter.pass.cpp | 87 ++ .../insert_iter_rv.pass.cpp | 73 ++ .../flat.set.modifiers/insert_range.pass.cpp | 105 +++ .../flat.set.modifiers/insert_rv.pass.cpp | 80 ++ .../insert_sorted_initializer_list.pass.cpp | 58 ++ .../insert_sorted_iter_iter.pass.cpp | 77 ++ .../insert_transparent.pass.cpp | 169 ++++ .../flat.set.modifiers/replace.pass.cpp | 72 ++ .../swap_exception.pass.cpp | 61 ++ .../flat.set.modifiers/swap_free.pass.cpp | 94 ++ .../flat.set.modifiers/swap_member.pass.cpp | 92 ++ .../flat.set/flat.set.observers/comp.pass.cpp | 72 ++ .../flat.set.operations/contains.pass.cpp | 69 ++ .../contains_transparent.pass.cpp | 70 ++ .../flat.set.operations/count.pass.cpp | 69 ++ .../count_transparent.pass.cpp | 71 ++ .../flat.set.operations/equal_range.pass.cpp | 77 ++ .../equal_range_transparent.pass.cpp | 97 ++ .../flat.set.operations/find.pass.cpp | 53 ++ .../find_transparent.pass.cpp | 88 ++ .../flat.set.operations/lower_bound.pass.cpp | 70 ++ .../lower_bound_transparent.pass.cpp | 94 ++ .../flat.set.operations/upper_bound.pass.cpp | 71 ++ .../upper_bound_transparent.pass.cpp | 93 ++ .../container.adaptors/flat.set/helpers.h | 294 ++++++ .../flat.set/incomplete_type.pass.cpp | 33 + .../flat.set/op_compare.pass.cpp | 105 +++ .../flat.set/types.compile.pass.cpp | 94 ++ 82 files changed, 8453 insertions(+) create mode 100644 libcxx/include/__flat_set/flat_set.h create mode 100644 libcxx/include/flat_set create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/helpers.h create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8dac823503d73f..75acf9f7899ff6 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -367,6 +367,7 @@ set(files __flat_map/sorted_equivalent.h __flat_map/sorted_unique.h __flat_map/utils.h + __flat_set/flat_set.h __format/buffer.h __format/concepts.h __format/container_adaptor.h @@ -986,6 +987,7 @@ set(files fenv.h filesystem flat_map + flat_set float.h format forward_list diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h new file mode 100644 index 00000000000000..c920632c453bf5 --- /dev/null +++ b/libcxx/include/__flat_set/flat_set.h @@ -0,0 +1,853 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FLAT_set_FLAT_SET_H +#define _LIBCPP___FLAT_set_FLAT_SET_H + +#include <__algorithm/lexicographical_compare_three_way.h> +#include <__algorithm/min.h> +#include <__algorithm/ranges_adjacent_find.h> +#include <__algorithm/ranges_equal.h> +#include <__algorithm/ranges_inplace_merge.h> +#include <__algorithm/ranges_lower_bound.h> +#include <__algorithm/ranges_partition_point.h> +#include <__algorithm/ranges_sort.h> +#include <__algorithm/ranges_unique.h> +#include <__algorithm/ranges_upper_bound.h> +#include <__algorithm/remove_if.h> +#include <__assert> +#include <__compare/synth_three_way.h> +#include <__concepts/swappable.h> +#include <__config> +#include <__cstddef/byte.h> +#include <__cstddef/ptrdiff_t.h> +#include <__flat_map/sorted_unique.h> +#include <__functional/invoke.h> +#include <__functional/is_transparent.h> +#include <__functional/operations.h> +#include <__fwd/vector.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/ranges_iterator_traits.h> +#include <__iterator/reverse_iterator.h> +#include <__memory/allocator_traits.h> +#include <__memory/uses_allocator.h> +#include <__memory/uses_allocator_construction.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/container_compatible_range.h> +#include <__ranges/drop_view.h> +#include <__ranges/from_range.h> +#include <__ranges/ref_view.h> +#include <__ranges/size.h> +#include <__ranges/subrange.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/container_traits.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_allocator.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_same.h> +#include <__utility/exception_guard.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include <__utility/scope_guard.h> +#include <__vector/vector.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template , class _KeyContainer = vector<_Key>> +class flat_set { + template + friend class flat_set; + + static_assert(is_same_v<_Key, typename _KeyContainer::value_type>); + static_assert(!is_same_v<_KeyContainer, std::vector>, "vector is not a sequence container"); + +public: + // types + using key_type = _Key; + using value_type = _Key; + using key_compare = __type_identity_t<_Compare>; + using value_compare = _Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename _KeyContainer::size_type; + using difference_type = typename _KeyContainer::difference_type; + using iterator = typename _KeyContainer::const_iterator; + using const_iterator = iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using container_type = _KeyContainer; + +private: + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = + uses_allocator::value; + + _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; + +public: + // [flat.set.cons], construct/copy/destroy + _LIBCPP_HIDE_FROM_ABI + flat_set() noexcept(is_nothrow_default_constructible_v<_KeyContainer> && is_nothrow_default_constructible_v<_Compare>) + : __keys_(), __compare_() {} + + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other) noexcept( + is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : __keys_(std::move(__other.__keys_)), __compare_(std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + // gcc does not like the `throw` keyword in a conditionally noexcept function + if constexpr (!(is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>)) { + throw; + } +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const key_compare& __comp) : __keys_(), __compare_(__comp) {} + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + __sort_and_unique(); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(), __compare_(__comp) { + insert(__first, __last); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(__first, __last), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg) + : flat_set(from_range, std::forward<_Range>(__rg), key_compare()) {} + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp) : flat_set(__comp) { + insert_range(std::forward<_Range>(__rg)); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(__il.begin(), __il.end(), __comp) {} + + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : flat_set(__ctor_uses_allocator_tag{}, __alloc, std::move(__other.__keys_), std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + throw; +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(sorted_unique, __first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, + _InputIterator __first, + _InputIterator __last, + const key_compare& __comp, + const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(sorted_unique, __first, __last); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert_range(std::forward<_Range>(__rg)); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert_range(std::forward<_Range>(__rg)); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(initializer_list __il) { + clear(); + insert(__il); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(flat_set&& __other) noexcept( + is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_Compare>) { + // No matter what happens, we always want to clear the other container before returning + // since we moved from it + auto __clear_other_guard = std::__make_scope_guard([&]() noexcept { __other.clear() /* noexcept */; }); + { + // If an exception is thrown, we have no choice but to clear *this to preserve invariants + auto __on_exception = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__other.__keys_); + __compare_ = std::move(__other.__compare_); + __on_exception.__complete(); + } + return *this; + } + + // iterators + _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + + _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return begin(); } + _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return end(); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + // [flat.set.capacity], capacity + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __keys_.empty(); } + + _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __keys_.size(); } + + _LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept { return __keys_.max_size(); } + + // [flat.set.modifiers], modifiers + template + _LIBCPP_HIDE_FROM_ABI pair emplace(_Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __try_emplace(std::forward<_Args>(__args)...); + } else { + return __try_emplace(_Key(std::forward<_Args>(__args)...)); + } + } + + template + _LIBCPP_HIDE_FROM_ABI iterator emplace_hint(const_iterator __hint, _Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __emplace_hint(std::move(__hint), std::forward<_Args>(__args)...); + } else { + return __emplace_hint(std::move(__hint), _Key(std::forward<_Args>(__args)...)); + } + } + + _LIBCPP_HIDE_FROM_ABI pair insert(const value_type& __x) { return emplace(__x); } + + _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { + return emplace(std::forward<_Kp>(__x)); + } + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, const value_type& __x) { + return emplace_hint(__hint, __x); + } + + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, value_type&& __x) { + return emplace_hint(__hint, std::move(__x)); + } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { + return emplace_hint(__hint, std::forward<_Kp>(__x)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, _InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { + if constexpr (ranges::sized_range<_Range>) { + __reserve(ranges::size(__range)); + } + + __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + } + + _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } + + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, initializer_list __il) { + insert(sorted_unique, __il.begin(), __il.end()); + } + + _LIBCPP_HIDE_FROM_ABI container_type extract() && { + auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; }); + auto __ret = std::move(__keys_); + return __ret; + } + + _LIBCPP_HIDE_FROM_ABI void replace(container_type&& __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys), "Either the key container is not sorted or it contains duplicates"); + auto __guard = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__keys); + __guard.__complete(); + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __position) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_iter = __keys_.erase(__position); + __on_failure.__complete(); + return __key_iter; + } + + // The following overload is the same as the iterator overload + // iterator erase(const_iterator __position); + + _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __x) { + auto __iter = find(__x); + if (__iter != end()) { + erase(__iter); + return 1; + } + return 0; + } + + template + requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + !is_convertible_v<_Kp &&, const_iterator>) + _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { + auto [__first, __last] = equal_range(__x); + auto __res = __last - __first; + erase(__first, __last); + return __res; + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_it = __keys_.erase(__first, __last); + __on_failure.__complete(); + return __key_it; + } + + _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __y) noexcept { + // warning: The spec has unconditional noexcept, which means that + // if any of the following functions throw an exception, + // std::terminate will be called. + // This is discussed in P2767, which hasn't been voted on yet. + ranges::swap(__compare_, __y.__compare_); + ranges::swap(__keys_, __y.__keys_); + } + + _LIBCPP_HIDE_FROM_ABI void clear() noexcept { __keys_.clear(); } + + // observers + _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __compare_; } + _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __compare_; } + + // set operations + _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __x) { return __find_impl(*this, __x); } + + _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { + return __find_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { + return __find_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { + return contains(__x) ? 1 : 0; + } + + _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { + return find(__x) != end(); + } + + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) { + return __equal_range_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) const { + return __equal_range_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { + return __equal_range_impl(*this, __x); + } + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { + return __equal_range_impl(*this, __x); + } + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const flat_set& __x, const flat_set& __y) { + return ranges::equal(__x, __y); + } + + friend _LIBCPP_HIDE_FROM_ABI auto operator<=>(const flat_set& __x, const flat_set& __y) { + return std::lexicographical_compare_three_way( + __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); + } + + friend _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __x, flat_set& __y) noexcept { __x.swap(__y); } + +private: + struct __ctor_uses_allocator_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_tag() = default; + }; + struct __ctor_uses_allocator_empty_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_empty_tag() = default; + }; + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), + __compare_(std::forward<_CompArg>(__comp)...) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc)), + __compare_(std::forward<_CompArg>(__comp)...) {} + + _LIBCPP_HIDE_FROM_ABI bool __is_sorted_and_unique(auto&& __key_container) const { + auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) { return !__compare_(__x, __y); }; + return ranges::adjacent_find(__key_container, __greater_or_equal_to) == ranges::end(__key_container); + } + + // This function is only used in constructors. So there is not exception handling in this function. + // If the function exits via an exception, there will be no flat_set object constructed, thus, there + // is no invariant state to preserve + _LIBCPP_HIDE_FROM_ABI void __sort_and_unique() { + ranges::sort(__keys_, __compare_); + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } else { + for (; __first != __last; ++__first) { + __keys_.insert(__keys_.end(), *__first); + } + } + if (size() != __old_size) { + if constexpr (!_WasSorted) { + ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); + } else { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__is_sorted_and_unique(__keys_ | ranges::views::drop(__old_size)), + "Either the key container is not sorted or it contains duplicates"); + } + ranges::inplace_merge(__keys_.begin(), __keys_.begin() + __old_size, __keys_.end(), __compare_); + + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + __on_failure.__complete(); + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __find_impl(_Self&& __self, const _Kp& __key) { + auto __it = __self.lower_bound(__key); + auto __last = __self.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return __last; + } + return __it; + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __equal_range_impl(_Self&& __self, const _Kp& __key) { + auto __it = ranges::lower_bound(__self.__keys_, __key, __self.__compare_); + auto __last = __self.__keys_.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return std::make_pair(__it, __it); + } + return std::make_pair(__it, std::next(__it)); + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_exact_pos(const_iterator __it, _KeyArg&& __key) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { + if constexpr (!__container_traits<_KeyContainer>::__emplacement_has_strong_exception_safety_guarantee) { + clear() /* noexcept */; + } + }); + auto __key_it = __keys_.emplace(__it, std::forward<_KeyArg>(__key)); + __on_failure.__complete(); + return __key_it; + } + + template + _LIBCPP_HIDE_FROM_ABI pair __try_emplace(_Kp&& __key) { + auto __it = lower_bound(__key); + if (__it == end() || __compare_(__key, *__it)) { + return pair(__emplace_exact_pos(__it, std::forward<_Kp>(__key)), true); + } else { + return pair(std::move(__it), false); + } + } + + template + _LIBCPP_HIDE_FROM_ABI bool __is_hint_correct(const_iterator __hint, _Kp&& __key) { + if (__hint != cbegin() && !__compare_(*(__hint - 1), __key)) { + return false; + } + if (__hint != cend() && __compare_(*__hint, __key)) { + return false; + } + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint(const_iterator __hint, _Kp&& __key) { + if (__is_hint_correct(__hint, __key)) { + if (__hint == cend() || __compare_(__key, *__hint)) { + return __emplace_exact_pos(__hint, std::forward<_Kp>(__key)); + } else { + // key equals + return __hint; + } + } else { + return __try_emplace(std::forward<_Kp>(__key)).first; + } + } + + _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __size) { + if constexpr (requires { __keys_.reserve(__size); }) { + __keys_.reserve(__size); + } + } + + template + friend typename flat_set<_Key2, _Compare2, _KeyContainer2>::size_type + erase_if(flat_set<_Key2, _Compare2, _KeyContainer2>&, _Predicate); + + _KeyContainer __keys_; + _LIBCPP_NO_UNIQUE_ADDRESS key_compare __compare_; + + struct __key_equiv { + _LIBCPP_HIDE_FROM_ABI __key_equiv(key_compare __c) : __comp_(__c) {} + _LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const { + return !__comp_(__x, __y) && !__comp_(__y, __x); + } + key_compare __comp_; + }; +}; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(_KeyContainer, _Compare = _Compare()) -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(_KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(_KeyContainer, _Compare, _Allocator) -> flat_set; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare = _Compare()) + -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(sorted_unique_t, _KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare, _Allocator) + -> flat_set; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(_InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >, + class _Allocator = allocator, + class = __enable_if_t::value && __is_allocator<_Allocator>::value>> +flat_set(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> flat_set< + ranges::range_value_t<_Range>, + _Compare, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template ::value>> +flat_set(from_range_t, _Range&&, _Allocator) -> flat_set< + ranges::range_value_t<_Range>, + less>, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template +struct uses_allocator, _Allocator> + : bool_constant> {}; + + template + _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type + erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; + } + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FLAT_set_FLAT_SET_H diff --git a/libcxx/include/flat_set b/libcxx/include/flat_set new file mode 100644 index 00000000000000..d03645fafafdba --- /dev/null +++ b/libcxx/include/flat_set @@ -0,0 +1,59 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_FLAT_SET +#define _LIBCPP_FLAT_SET + +/* + Header synopsis + +#include // see [compare.syn] +#include // see [initializer.list.syn] + +namespace std { + // [flat.set], class template flat_set + template, class KeyContainer = vector> + class flat_set; + + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + + template + struct uses_allocator, Allocator>; + + // [flat.set.erasure], erasure for flat_set + template + typename flat_set::size_type + erase_if(flat_set& c, Predicate pred); +} +*/ + +#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +# include <__cxx03/__config> +#else +# include <__config> + +# if _LIBCPP_STD_VER >= 23 +# include <__flat_map/sorted_unique.h> +# include <__flat_set/flat_set.h> +# endif + +// for feature-test macros +# include + +// standard required includes +# include +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif +#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) + +#endif // _LIBCPP_FLAT_SET diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4bae02137b37b2..abc351d5923963 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1263,6 +1263,17 @@ module std [system] { export * } + module flat_set { + module flat_set { + header "__flat_set/flat_set.h" + export std.vector.vector + export std.vector.fwd + } + + header "flat_set" + export * + } + module format { module buffer { header "__format/buffer.h" diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp new file mode 100644 index 00000000000000..204df1d681af1b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m; + ASSERT_SAME_TYPE(decltype(m.empty()), bool); + ASSERT_NOEXCEPT(m.empty()); + assert(m.empty()); + assert(std::as_const(m).empty()); + m = {1}; + assert(!m.empty()); + m.clear(); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp new file mode 100644 index 00000000000000..161fe533eabacb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include + +void f() { + std::flat_set c; + c.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp new file mode 100644 index 00000000000000..cd7f424e00ece2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type max_size() const noexcept; + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_allocator.h" +#include "test_macros.h" + +int main(int, char**) { + { + using A1 = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= 10); + LIBCPP_ASSERT(c.max_size() == 10); + } + { + using A = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + LIBCPP_ASSERT(c.max_size() == max_dist); + } + { + typedef std::flat_set C; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + assert(c.max_size() <= alloc_max_size(std::allocator())); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp new file mode 100644 index 00000000000000..7c156e95ecb1c8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type size() const noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using M = std::flat_set, KeyContainer>; + using S = typename M::size_type; + { + const M m = {1, 1, 4, 5, 5}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 3); + } + { + const M m = {1}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 1); + } + { + const M m; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 0); + } + { + M m; + S s = 1000000; + for (auto i = 0u; i < s; ++i) { + m.emplace(i); + } + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == s); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp new file mode 100644 index 00000000000000..acc0817d7cac4d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// explicit flat_set(const Allocator& a); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // explicit + using M = std::flat_set, std::vector>>; + + static_assert(std::is_constructible_v>); + static_assert(!std::is_convertible_v, M>); + } + { + using A = test_allocator; + using M = std::flat_set, std::vector>>; + M m(A(0, 5)); + assert(m.empty()); + assert(m.begin() == m.end()); + auto v = std::move(m).extract(); + assert(v.get_allocator().get_id() == 5); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp new file mode 100644 index 00000000000000..7f75f1e1611e3b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(initializer_list il); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m = {8, 10}; + assert(m.size() == 2); + m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + int expected[] = {1, 2, 3, 4, 5, 6}; + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + } + { + M m = {10, 8}; + assert(m.size() == 2); + m = {3}; + int expected[] = {3}; + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp new file mode 100644 index 00000000000000..b3bee18f5a936b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(const key_compare& comp); +// template +// flat_set(const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + auto m = std::flat_set(C(3)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(3)); + } + { + // The one-argument ctor is explicit. + using C = test_less; + static_assert(std::is_constructible_v, C>); + static_assert(!std::is_convertible_v>); + + static_assert(std::is_constructible_v, std::less>); + static_assert(!std::is_convertible_v, std::flat_set>); + } + { + using C = test_less; + using A1 = test_allocator; + auto m = std::flat_set>(C(4), A1(5)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + { + // explicit(false) + using C = test_less; + using A1 = test_allocator; + std::flat_set> m = {C(4), A1(5)}; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp new file mode 100644 index 00000000000000..3d1e6240c952e8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -0,0 +1,158 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(container_type key_cont, const key_compare& comp = key_compare()); +// template +// flat_set(const container_type& key_cont, const Allocator& a); +// template +// flat_set(const container_type& key_cont, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(container_type) + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + + // explicit + static_assert(std::is_constructible_v&>); + static_assert(!ImplicitlyConstructible&>); + } + { + // flat_set(container_type) + // move-only + MoveOnly expected[] = {3, 2, 1}; + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks; + ks.push_back(1); + ks.push_back(3); + ks.push_back(2); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(container_type) + // container's allocator is used + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(5)); + } + { + // flat_set(container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + + // explicit + static_assert(std::is_constructible_v&, const C&>); + static_assert(!ImplicitlyConstructible&, const C&>); + } + { + // flat_set(container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(ks, A(4)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , const Allocator&) + // explicit(false) + using A = test_allocator; + using M = std::flat_set, std::deque>; + static_assert(ImplicitlyConstructible&, const A&>); + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + M m = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4), A(5)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + auto m_copy = m; + auto keys = std::move(m_copy).extract(); + assert(keys.get_allocator() == A(5)); + + // explicit(false) + static_assert(ImplicitlyConstructible&, const A&>); + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + keys = std::move(m2).extract(); + assert(keys.get_allocator() == A(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp new file mode 100644 index 00000000000000..f1dbc955e1b0de --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(-2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp new file mode 100644 index 00000000000000..59fb9d0a38366f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M(mo, test_allocator(3)); + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(3)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp new file mode 100644 index 00000000000000..169b469f3bca68 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& s); + +// Validate whether the container can be copy-assigned (move-assigned, swapped) +// with an ADL-hijacking operator& + +#include +#include + +#include "test_macros.h" +#include "operator_hijacker.h" + +void test() { + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp new file mode 100644 index 00000000000000..cdd5045f4bb9f7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // test_allocator is not propagated + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M({{3, 4, 5}}, C(3), test_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + // other_allocator is propagated + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = M({3, 4, 5}, C(3), other_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + { + // comparator is copied and invariant is preserved + using M = std::flat_set>; + M mo = M({1, 2}, std::less()); + M m = M({1, 2}, std::greater()); + assert(m.key_comp()(2, 1) == true); + assert(m != mo); + m = mo; + assert(m.key_comp()(2, 1) == false); + assert(m == mo); + } + { + // self-assignment + using M = std::flat_set; + M m = {{1, 2}}; + m = static_cast(m); + assert((m == M{{1, 2}})); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp new file mode 100644 index 00000000000000..5db8c4ca722466 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Test CTAD on cases where deduction should fail. + +#include +#include +#include +#include +#include + +struct NotAnAllocator { + friend bool operator<(NotAnAllocator, NotAnAllocator) { return false; } +}; + +template +concept CanDeductFlatSet = requires { std::flat_set{std::declval()...}; }; + +static_assert(CanDeductFlatSet, std::vector>); + +// cannot deduce Key and T from nothing +static_assert(!CanDeductFlatSet<>); + +// cannot deduce Key and T from just (KeyContainer), even if it's a container of pairs +static_assert(!CanDeductFlatSet>>); + +// cannot deduce Key and T from just (KeyContainer, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>>); + +// cannot deduce Key and T from just (Compare) +static_assert(!CanDeductFlatSet>); + +// cannot deduce Key and T from just (Compare, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>); + +// cannot deduce Key and T from just (Allocator) +static_assert(!CanDeductFlatSet>); + +// cannot convert from some arbitrary unrelated type +static_assert(!CanDeductFlatSet); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp new file mode 100644 index 00000000000000..612e64a7c42f23 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -0,0 +1,341 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "deduction_guides_sfinae_checks.h" +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_copy() { + { + std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set s(source); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s{source}; // braces instead of parens + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s(source, std::allocator()); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } +} + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(ks, vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(ks, vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_iter_iter() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m(std::begin(arr), std::end(arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) + static_assert(std::is_same_v>); + assert(s.size() == 3); + } +} + +void test_iter_iter_compare() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m(std::begin(arr), std::end(arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } +} + +void test_initializer_list() { + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } + { + using M = std::flat_set; + M m; + std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + assert(s[m] == m); + } +} + +void test_initializer_list_compare() { + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } +} + +void test_from_range() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(std::from_range, r); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +void test_from_range_compare() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(std::from_range, r, std::greater()); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +int main(int, char**) { + // Each test function also tests the sorted_unique-prefixed and allocator-suffixed overloads. + test_copy(); + test_containers(); + test_containers_compare(); + test_iter_iter(); + test_iter_iter_compare(); + test_initializer_list(); + test_initializer_list_compare(); + test_from_range(); + test_from_range_compare(); + + AssociativeContainerDeductionGuidesSfinaeAway>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp new file mode 100644 index 00000000000000..df8d6d885ee524 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + const int expected[] = {1, 2, 3, INT_MAX}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + const int expected[] = {INT_MAX, 3, 2, 1}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +int main(int, char**) { + test_containers(); + test_containers_compare(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp new file mode 100644 index 00000000000000..64b0bfcb383a72 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + std::flat_set m; + assert(m.empty()); + } + { + // explicit(false) + std::flat_set m = {}; + assert(m.empty()); + } + { + std::flat_set>> m; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp().default_constructed_); + } + { + using A1 = explicit_allocator; + using A2 = explicit_allocator; + { + std::flat_set> m; + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + { + A1 a1; + std::flat_set> m(a1); + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp new file mode 100644 index 00000000000000..b4a3b6de205a31 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set() +// noexcept( +// is_nothrow_default_constructible_v && +// is_nothrow_default_constructible_v); + +// This tests a conforming extension + +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +int main(int, char**) { +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp new file mode 100644 index 00000000000000..c0d315c0ce74b4 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// ~flat_set(); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingDtorComp { + bool operator()(const auto&, const auto&) const; + ~ThrowingDtorComp() noexcept(false) {} +}; + +int main(int, char**) { + { + using C = std::flat_set; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::vector>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::deque>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(!std::is_nothrow_destructible_v); + C c; + } +#endif // _LIBCPP_VERSION + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp new file mode 100644 index 00000000000000..cd2319e91f760d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -0,0 +1,151 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(initializer_list il, const key_compare& comp = key_compare()); +// template +// flat_set(initializer_list il, const Alloc& a); +// template +// flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +#include "../../../test_compare.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + } + + int expected[] = {1, 2, 3, 5}; + { + // flat_set(initializer_list); + using M = std::flat_set; + std::initializer_list il = {5, 2, 2, 3, 1, 3}; + M m(il); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + // explicit(false) + using M = std::flat_set; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + using M = std::flat_set, std::deque>>; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + { + using A = explicit_allocator; + { + // flat_set(initializer_list); + // different comparator + using M = std::flat_set>; + M m = {1, 2, 3}; + assert(m.size() == 1); + LIBCPP_ASSERT(*m.begin() == 1); + assert(m.key_comp().default_constructed_); + } + { + // flat_set(initializer_list, const Allocator&); + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + } + { + // flat_set(initializer_list, const key_compare&); + using C = test_less; + using M = std::flat_set; + auto m = M({5, 2, 2, 3, 1, 3}, C(10)); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + assert(m.key_comp() == C(10)); + + // explicit(false) + M m2 = {{5, 2, 2, 1, 3, 3}, C(10)}; + assert(m2 == m); + assert(m2.key_comp() == C(10)); + } + { + // flat_set(initializer_list, const key_compare&); + // Sorting uses the comparator that was passed in + using M = std::flat_set, std::deque>>; + auto m = M({5, 2, 2, 1, 3, 1}, std::greater()); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + assert(m.key_comp()(2, 1) == true); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using A = explicit_allocator; + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, {}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp new file mode 100644 index 00000000000000..65eebc21a66c4c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(InputIterator first, InputIterator last, const Allocator& a); +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(InputIterator , InputIterator) + // cpp17_input_iterator + using M = std::flat_set; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)}; + assert(m2 == m); + } + { + // flat_set(InputIterator , InputIterator) + // greater + using M = std::flat_set, std::deque>>; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(InputIterator , InputIterator) + // Test when the operands are of array type (also contiguous iterator type) + using M = std::flat_set, std::vector>>; + auto m = M(ar, ar); + assert(m.empty()); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&) + using C = test_less; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {ar, ar + 9, C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + auto m = M(ar, ar + 9, A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + M m = {ar, ar + 9, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {ar, ar + 9, {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp new file mode 100644 index 00000000000000..69b340ad09fe15 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A(7)); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A(7)); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().get_id() == test_alloc_base::moved_value); + } + { + using C = test_less; + using A = min_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A()); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A()); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A()); + } + { + // A moved-from flat_set maintains its class invariant in the presence of moved-from comparators. + using M = std::flat_set>; + M mo = M({1, 2, 3}, std::less()); + M m = std::move(mo); + assert(m.size() == 3); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.key_comp()(1, 2) == true); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + LIBCPP_ASSERT(m.key_comp()(1, 2) == true); + LIBCPP_ASSERT(mo.empty()); + mo.insert({1, 2, 3}); // insert has no preconditions + assert(m == mo); + } + { + // moved-from object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m1.size() == 0); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp new file mode 100644 index 00000000000000..fc7f68d8c967ad --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + int expected[] = {1, 2, 3}; + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + auto mo = M(expected, expected + 3, C(5), A(7)); + auto m = M(std::move(mo), A(3)); + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(3)); + assert(std::ranges::equal(keys, expected )); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A(7)); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2(std::move(m1), std::allocator{}); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp new file mode 100644 index 00000000000000..b16dc38dd40285 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{4, 5})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + m = std::move(mo); + assert((m == M{5, 4, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A()); + assert(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp new file mode 100644 index 00000000000000..50817f4be8a812 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); +// Preserves the class invariant for the moved-from flat_set. + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +int main(int, char**) { + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp new file mode 100644 index 00000000000000..86f3568f0d67a6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&& c) +// noexcept( +// is_nothrow_move_assignable::value && +// is_nothrow_move_assignable::value && +// is_nothrow_copy_assignable::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_macros.h" + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp new file mode 100644 index 00000000000000..17e4e40387606c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// flat_set(flat_set&& s); +// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +int main(int, char**) { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp new file mode 100644 index 00000000000000..49d1151fd8a993 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&) +// noexcept(is_nothrow_move_constructible::value && +// is_nothrow_move_constructible::value && +// is_nothrow_copy_constructible::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp new file mode 100644 index 00000000000000..785718d2eed333 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -0,0 +1,322 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +// Test various constructors with pmr + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // flat_set(const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::polymorphic_allocator pa = &mr; + auto m1 = M(pa); + assert(m1.empty()); + assert(std::move(m1).extract().get_allocator() == pa); + auto m2 = M(&mr); + assert(m2.empty()); + assert(std::move(m2).extract().get_allocator() == pa); + } + { + // flat_set(const key_compare& comp, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::greater()); + assert(vm[0] == M{}); + assert(vm[0].key_comp()(2, 1) == true); + assert(vm[0].value_comp()(2, 1) == true); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + // const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + assert(ks.get_allocator().resource() != &mr); + vm.emplace_back(ks); + assert(ks.size() == 9); // ks' value is unchanged, since it was an lvalue above + assert((vm[0] == M{1, 2, 3})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const flat_set&, const allocator_type&); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, C(5), &mr1); + M m = {mo, &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + auto keys = std::move(m).extract(); + assert((keys == std::pmr::vector{1, 2, 3})); + assert(keys.get_allocator().resource() == &mr2); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + auto keys2 = std::move(mo).extract(); + assert((keys2 == std::pmr::vector{1, 2, 3})); + assert(keys2.get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set&, const allocator_type&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::vector vs; + M m = {1, 2, 3}; + vs.push_back(m); + assert(vs[0] == m); + } + { + // flat_set& operator=(const flat_set& m); + // pmr allocator is not propagated + using M = std::flat_set, std::pmr::deque>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, &mr1); + M m = M({4, 5}, &mr2); + m = mo; + assert((m == M{1, 2, 3})); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // mo is unchanged + assert((mo == M{1, 2, 3})); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set& m); + using C = test_less; + std::pmr::monotonic_buffer_resource mr; + using M = std::flat_set>; + auto mo = M({1, 2, 3}, C(5), &mr); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert((m == M{1, 2, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator().resource() == std::pmr::get_default_resource()); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert((mo == M{1, 2, 3})); + auto kso = std::move(mo).extract(); + assert(kso.get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il, C(5)); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + assert(vm[0].key_comp() == C(5)); + } + { + // flat_set(InputIterator first, InputIterator last, const Allocator& a); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // cpp17 iterator + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(ar, ar); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(flat_set&&, const allocator_type&); + int expected[] = {1, 2, 3}; + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 3, 1, 2}, C(5), &mr1); + M m = {std::move(mo), &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + assert(std::equal(m.begin(), m.end(), expected, expected + 3)); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(flat_set&&, const allocator_type&); + using M = std::flat_set, std::pmr::deque>; + std::pmr::vector vs; + M m = {1, 3, 1, 2}; + vs.push_back(std::move(m)); + assert((std::move(vs[0]).extract() == std::pmr::deque{1, 2, 3})); + } + { + // flat_set& operator=(flat_set&&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = + M({"short", "very long string that definitely won't fit in the SSO buffer and therefore becomes empty on move"}, + &mr1); + M m = M({"don't care"}, &mr2); + m = std::move(mo); + assert(m.size() == 2); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.begin()->get_allocator().resource() == &mr2); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + mo.insert("foo"); + assert(mo.begin()->get_allocator().resource() == &mr1); + } + { + // flat_set(from_range_t, R&&, const Alloc&); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // input_range + using M = std::flat_set, std::pmr::vector>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(ar, ar)); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 2, 4, 10}; + vm.emplace_back(std::sorted_unique, ks); + assert(!ks.empty()); // it was an lvalue above + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, const container_type& key_cont,const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks({1, 2, 4, 10}, &mr); + vm.emplace_back(std::sorted_unique, ks); + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp new file mode 100644 index 00000000000000..bb9f99c228bfec --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -0,0 +1,173 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// flat_set(from_range_t, R&&) +// template R> +// flat_set(from_range_t, R&&, const key_compare&) +// template R, class Alloc> +// flat_set(from_range_t, R&&, const Alloc&); +// template R, class Alloc> +// flat_set(from_range_t, R&&, const key_compare&, const Alloc&); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +// test constraint container-compatible-range + +template +using RangeOf = std::ranges::subrange; +using Set = std::flat_set; + +static_assert(std::is_constructible_v>); +static_assert(std::is_constructible_v>); +static_assert(!std::is_constructible_v>>); + +static_assert(std::is_constructible_v, std::less>); +static_assert(std::is_constructible_v, std::less>); +static_assert(!std::is_constructible_v>, std::less>); + +static_assert(std::is_constructible_v, std::allocator>); +static_assert(std::is_constructible_v, std::allocator>); +static_assert(!std::is_constructible_v>, std::allocator>); + +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert( + !std:: + is_constructible_v>, std::less, std::allocator>); + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(from_range_t, R&&) + // input_range && !common + using M = std::flat_set; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))}; + assert(m2 == m); + } + { + // flat_set(from_range_t, R&&) + // greater + using M = std::flat_set, std::deque>>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(from_range_t, R&&) + // contiguous range + using M = std::flat_set; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9)); + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(from_range_t, R&&, const key_compare&) + using C = test_less; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {std::from_range, R(ar, ar + 9), C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp new file mode 100644 index 00000000000000..2d442d49667bd0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(sorted_unique_t, container_type key_cont, const key_compare& comp = key_compare()); +// +// template +// flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); +// template +// flat_set(sorted_unique_t, const container_type& key_cont, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, container_type) + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + auto ks2 = ks; + + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + + // explicit(false) + M m2 = {std::sorted_unique, std::move(ks2)}; + assert(m == m2); + } + { + // flat_set(sorted_unique_t, container_type) + // non-default container, comparator and allocator type + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks = {10, 4, 2, 1}; + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + } + { + // flat_set(sorted_unique_t, container_type) + // allocator copied into the containers + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + assert(std::move(m).extract().get_allocator() == A(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + + auto m = M(std::sorted_unique, ks, C(4)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, C(4)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 2, 4, 10}; + auto m = M(std::sorted_unique, ks, C(4), A(5)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + assert(M(m).extract().get_allocator() == A(5)); + + // explicit(false) + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + assert(std::move(m2).extract().get_allocator() == A(5)); + } + { + // flat_set(sorted_unique_t, container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, ks, A(6)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 4, 10})); + assert(M(m).extract().get_allocator() == A(6)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, A(6)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp new file mode 100644 index 00000000000000..01956a78c7f48d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t s, initializer_list il, +// const key_compare& comp = key_compare()) +// template +// flat_set(sorted_unique_t, initializer_list il, const Alloc& a); +// template +// flat_set(sorted_unique_t, initializer_list il, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +std::initializer_list il = {1, 2, 4, 5}; + +const auto il1 = il; +const auto il2 = il; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + } + + { + // flat_set(sorted_unique_t, initializer_list); + using M = std::flat_set; + auto m = M(std::sorted_unique, il1); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, il1}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + using M = std::flat_set>; + auto m = M(std::sorted_unique, il1, std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, il1, std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + std::initializer_list il4{5, 4, 2, 1}; + auto m = M(std::sorted_unique, il4, std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, initializer_list, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + auto m = M(std::sorted_unique, il2, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, il2, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(std::sorted_unique, il2, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {std::sorted_unique, il2, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp new file mode 100644 index 00000000000000..b5229a84dd5133 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // cpp17_input_iterator + using M = std::flat_set; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // cpp_17_input_iterator + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + int ar[] = {5, 4, 2, 1}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[1] = {42}; + auto m = M(std::sorted_unique, ar, ar, C(5)); + assert(m.empty()); + assert(m.key_comp() == C(5)); + } + { + // flat_set(sorted_unique_t, InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, ar, ar + 4, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + int ar[] = {1, 2, 4, 5}; + M m = {std::sorted_unique, ar, ar + 4, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp new file mode 100644 index 00000000000000..134db83aef3cad --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "min_allocator.h" + +// Verify that `flat_set` (like `set`) does NOT support std::erase. +// +template +concept HasStdErase = requires(S& s, typename S::value_type x) { std::erase(s, x); }; +static_assert(HasStdErase>); +static_assert(!HasStdErase>); + +template +M make(std::initializer_list vals) { + M ret; + for (int v : vals) + ret.emplace(v); + return ret; +} + +template +void test0( + std::initializer_list vals, Pred p, std::initializer_list expected, std::size_t expected_erased_count) { + M s = make(vals); + ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p))); + assert(expected_erased_count == std::erase_if(s, p)); + assert(s == make(expected)); +} + +template +void test() { + // Test all the plausible signatures for this predicate. + auto is1 = [](typename S::const_reference v) { return v == 1; }; + auto is2 = [](typename S::value_type v) { return v == 2; }; + auto is3 = [](const typename S::value_type& v) { return v == 3; }; + auto is4 = [](auto v) { return v == 4; }; + auto True = [](const auto&) { return true; }; + auto False = [](auto&&) { return false; }; + + test0({}, is1, {}, 0); + + test0({1}, is1, {}, 1); + test0({1}, is2, {1}, 0); + + test0({1, 2}, is1, {2}, 1); + test0({1, 2}, is2, {1}, 1); + test0({1, 2}, is3, {1, 2}, 0); + + test0({1, 2, 3}, is1, {2, 3}, 1); + test0({1, 2, 3}, is2, {1, 3}, 1); + test0({1, 2, 3}, is3, {1, 2}, 1); + test0({1, 2, 3}, is4, {1, 2, 3}, 0); + + test0({1, 2, 3}, True, {}, 3); + test0({1, 2, 3}, False, {1, 2, 3}, 0); +} + +int main(int, char**) { + test>(); + test, std::vector>>>(); + test, std::vector>>>(); + test, std::deque>>>(); + test, std::deque>>>(); + test>(); + test>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp new file mode 100644 index 00000000000000..6bbe1ad4f01670 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -0,0 +1,128 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); +// If any member function in [flat.set.defn] exits via an exception, the invariant is restored. +// (This is not a member function, but let's respect the invariant anyway.) + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct Counter { + int c1, c2, throws; + void tick() { + c1 -= 1; + if (c1 == 0) { + c1 = c2; + throws += 1; + throw 42; + } + } +}; +Counter g_counter = {0, 0, 0}; + +struct ThrowingAssignment { + ThrowingAssignment(int i) : i_(i) {} + ThrowingAssignment(const ThrowingAssignment&) = default; + ThrowingAssignment& operator=(const ThrowingAssignment& rhs) { + g_counter.tick(); + i_ = rhs.i_; + g_counter.tick(); + return *this; + } + operator int() const { return i_; } + int i_; +}; + +struct ThrowingComparator { + bool operator()(const ThrowingAssignment& a, const ThrowingAssignment& b) const { + g_counter.tick(); + return a.i_ < b.i_; + } +}; + +struct ErasurePredicate { + bool operator()(const auto& x) const { return (3 <= x && x <= 5); } +}; + +int main(int, char**) { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + { + using M = std::flat_set; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + M m = M({1, 2, 3, 4, 5, 6, 7, 8}); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + + { + using M = std::flat_set>; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + std::deque container = {5, 6, 7, 8}; + container.insert(container.begin(), {1, 2, 3, 4}); + M m = M(std::move(container)); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp new file mode 100644 index 00000000000000..c07297a141ad10 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator begin() noexcept; +// const_iterator begin() const noexcept +// iterator end() noexcept; +// const_iterator end() const noexcept; +// +// const_iterator cbegin() const noexcept; +// const_iterator cend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.begin()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cbegin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.begin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(m.end()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cend()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.end()), typename M::const_iterator); + static_assert(noexcept(m.begin())); + static_assert(noexcept(cm.begin())); + static_assert(noexcept(m.cbegin())); + static_assert(noexcept(m.end())); + static_assert(noexcept(cm.end())); + static_assert(noexcept(m.cend())); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(std::distance(cm.begin(), cm.end()) == 4); + assert(std::distance(m.cbegin(), m.cend()) == 4); + typename M::iterator i; // default-construct + i = m.begin(); // move-assignment + typename M::const_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 1; j <= 4; ++j, ++i) { // pre-increment + assert(*i == j); // operator* + } + assert(i == m.end()); + for (int j = 4; j >= 1; --j) { + --i; // pre-decrement + assert((*i) == j); + } + assert(i == m.begin()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // N3644 testing + using C = std::flat_set; + C::iterator ii1{}, ii2{}; + C::iterator ii4 = ii1; + C::const_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp new file mode 100644 index 00000000000000..29441dcc57d40e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set iterators should be C++20 random access iterators + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using KI = typename KeyContainer::iterator; + using I = M::iterator; + using CI = M::const_iterator; + using RI = M::reverse_iterator; + using CRI = M::const_reverse_iterator; + + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + + M m = {1, 2, 3, 4}; + + I i1 = m.begin(); + I i2 = m.begin() + 1; + + assert(i1 == i1); + assert(!(i1 != i1)); + assert(i1 != i2); + assert(!(i1 == i2)); + assert(i1 < i2); + assert(!(i1 < i1)); + assert(i1 <= i1); + assert(i1 <= i2); + assert(!(i2 <= i1)); + assert(i2 > i1); + assert(!(i2 > i2)); + assert(i2 >= i1); + assert(i2 >= i2); + assert(!(i1 >= i2)); + + CI ci1 = m.cbegin(); + CI ci2 = m.cbegin() + 1; + assert(ci1 == ci1); + assert(!(ci1 != ci1)); + assert(ci1 != ci2); + assert(!(ci1 == ci2)); + assert(ci1 < ci2); + assert(!(ci1 < ci1)); + assert(ci1 <= ci1); + assert(ci1 <= ci2); + assert(!(ci2 <= ci1)); + assert(ci2 > ci1); + assert(!(ci2 > ci2)); + assert(ci2 >= ci1); + assert(ci2 >= ci2); + assert(!(ci1 >= ci2)); + + RI ri1 = m.rbegin(); + RI ri2 = m.rbegin() + 1; + assert(ri1 == ri1); + assert(!(ri1 != ri1)); + assert(ri1 != ri2); + assert(!(ri1 == ri2)); + assert(ri1 < ri2); + assert(!(ri1 < ri1)); + assert(ri1 <= ri1); + assert(ri1 <= ri2); + assert(!(ri2 <= ri1)); + assert(ri2 > ri1); + assert(!(ri2 > ri2)); + assert(ri2 >= ri1); + assert(ri2 >= ri2); + assert(!(ri1 >= ri2)); + + CRI cri1 = m.crbegin(); + CRI cri2 = m.crbegin() + 1; + assert(cri1 == cri1); + assert(!(cri1 != cri1)); + assert(cri1 != cri2); + assert(!(cri1 == cri2)); + assert(cri1 < cri2); + assert(!(cri1 < cri1)); + assert(cri1 <= cri1); + assert(cri1 <= cri2); + assert(!(cri2 <= cri1)); + assert(cri2 > cri1); + assert(!(cri2 > cri2)); + assert(cri2 >= cri1); + assert(cri2 >= cri2); + assert(!(cri1 >= cri2)); + + if constexpr (std::three_way_comparable) { + static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::same_as I()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as RI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + + assert(i1 <=> i1 == std::strong_ordering::equivalent); + assert(i1 <=> i2 == std::strong_ordering::less); + assert(i2 <=> i1 == std::strong_ordering::greater); + + assert(ci1 <=> ci1 == std::strong_ordering::equivalent); + assert(ci1 <=> ci2 == std::strong_ordering::less); + assert(ci2 <=> ci1 == std::strong_ordering::greater); + + assert(ri1 <=> ri1 == std::strong_ordering::equivalent); + assert(ri1 <=> ri2 == std::strong_ordering::less); + assert(ri2 <=> ri1 == std::strong_ordering::greater); + + assert(cri1 <=> cri1 == std::strong_ordering::equivalent); + assert(cri1 <=> cri2 == std::strong_ordering::less); + assert(cri2 <=> cri1 == std::strong_ordering::greater); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp new file mode 100644 index 00000000000000..35b45b6e797233 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator, const_iterator, reverse_iterator, const_reverse_iterator + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + using I = C::iterator; + using CI = C::const_iterator; + using RI = C::reverse_iterator; + using CRI = C::const_reverse_iterator; + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp new file mode 100644 index 00000000000000..4ec64e706b7021 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include +#include +#include +#include +#include +#include "MinSequenceContainer.h" +#include "min_allocator.h" + +template +void test() { + { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + + static_assert(std::same_as, typename C::iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(std::ranges::viewable_range); + + static_assert(std::same_as, typename C::const_iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(!std::ranges::viewable_range); + } +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp new file mode 100644 index 00000000000000..a16383cdcf5383 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// reverse_iterator rbegin() noexcept; +// const_reverse_iterator rbegin() const noexcept; +// reverse_iterator rend() noexcept; +// const_reverse_iterator rend() const noexcept; +// +// const_reverse_iterator crbegin() const noexcept; +// const_reverse_iterator crend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include + +#include "test_macros.h" +#include + +int main(int, char**) { + { + using M = std::flat_set, std::deque>; + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.rbegin()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.rend()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crend()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rend()), M::const_reverse_iterator); + static_assert(noexcept(m.rbegin())); + static_assert(noexcept(cm.rbegin())); + static_assert(noexcept(m.crbegin())); + static_assert(noexcept(m.rend())); + static_assert(noexcept(cm.rend())); + static_assert(noexcept(m.crend())); + assert(m.size() == 4); + assert(std::distance(m.rbegin(), m.rend()) == 4); + assert(std::distance(cm.rbegin(), cm.rend()) == 4); + assert(std::distance(m.crbegin(), m.crend()) == 4); + assert(std::distance(cm.crbegin(), cm.crend()) == 4); + M::reverse_iterator i; // default-construct + ASSERT_SAME_TYPE(decltype(*i), const int&); + i = m.rbegin(); // move-assignment + M::const_reverse_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 4; j >= 1; --j, ++i) { // pre-increment + assert(*i == j); + } + assert(i == m.rend()); + for (int j = 1; j <= 4; ++j) { + --i; // pre-decrement + assert(*i == j); + } + assert(i == m.rbegin()); + } + { + // N3644 testing + using C = std::flat_set; + C::reverse_iterator ii1{}, ii2{}; + C::reverse_iterator ii4 = ii1; + C::const_reverse_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp new file mode 100644 index 00000000000000..221a13fa057577 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// void clear() noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// test noexcept + +template +concept NoExceptClear = requires(T t) { + { t.clear() } noexcept; +}; + +static_assert(NoExceptClear>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptClear, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4, 5}; + assert(m.size() == 5); + ASSERT_NOEXCEPT(m.clear()); + ASSERT_SAME_TYPE(decltype(m.clear()), void); + m.clear(); + assert(m.size() == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp new file mode 100644 index 00000000000000..95f7a3c5f5d34a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -0,0 +1,141 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// pair emplace(Args&&... args); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the begin + M m = {3, 5, 6, 7}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted in the middle + M m = {0, 1, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the end + M m = {0, 1}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } + { + // key already exists and original at the begin + M m = {2, 3, 5, 6}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original in the middle + M m = {0, 2, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 1); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original at the end + M m = {0, 1, 2}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace()), R); + R r = m.emplace(2, 0.0); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace(1, 3.5); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace(1, 3.5); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp new file mode 100644 index 00000000000000..de855d5e5c3009 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// iterator emplace_hint(const_iterator position, Args&&... args); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace_hint(m.end(), typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + } + { + // hints correct at the begin + M m = {3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints correct at the end + M m = {0, 1}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct but key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the begin + M m = {1, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrectly in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 1; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the end + M m = {0, 3}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrect and key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace_hint(m.cbegin())), R); + R r = m.emplace_hint(m.end(), 2, 0.0); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp new file mode 100644 index 00000000000000..386af04d26e9a2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(iterator position); +// iterator erase(const_iterator position); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(std::next(m.cbegin(), 3)); + assert(m.size() == 7); + assert(i1 == std::next(m.begin(), 3)); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 5); + assert(*std::next(m.begin(), 4) == 6); + assert(*std::next(m.begin(), 5) == 7); + assert(*std::next(m.begin(), 6) == 8); + + std::same_as decltype(auto) i2 = m.erase(std::next(m.begin(), 0)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 5)); + assert(m.size() == 5); + assert(i3 == m.end()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + + std::same_as decltype(auto) i4 = m.erase(std::next(m.begin(), 1)); + assert(m.size() == 4); + assert(i4 == std::next(m.begin())); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 6); + assert(*std::next(m.begin(), 3) == 7); + + std::same_as decltype(auto) i5 = m.erase(std::next(m.cbegin(), 2)); + assert(m.size() == 3); + assert(i5 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 7); + + std::same_as decltype(auto) i6 = m.erase(std::next(m.begin(), 2)); + assert(m.size() == 2); + assert(i6 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + + std::same_as decltype(auto) i7 = m.erase(std::next(m.cbegin(), 0)); + assert(m.size() == 1); + assert(i7 == std::next(m.begin(), 0)); + assert(*m.begin() == 5); + + std::same_as decltype(auto) i8 = m.erase(m.begin()); + assert(m.size() == 0); + assert(i8 == m.begin()); + assert(i8 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp new file mode 100644 index 00000000000000..7416977844e5df --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(const_iterator first, const_iterator last); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(m.cbegin(), m.cbegin()); + assert(m.size() == 8); + assert(i1 == m.begin()); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 4); + assert(*std::next(m.begin(), 4) == 5); + assert(*std::next(m.begin(), 5) == 6); + assert(*std::next(m.begin(), 6) == 7); + assert(*std::next(m.begin(), 7) == 8); + + std::same_as decltype(auto) i2 = m.erase(m.cbegin(), std::next(m.cbegin(), 2)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 2), std::next(m.cbegin(), 6)); + assert(m.size() == 2); + assert(i3 == std::next(m.begin(), 2)); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + + std::same_as decltype(auto) i4 = m.erase(m.cbegin(), m.cend()); + assert(m.size() == 0); + assert(i4 == m.begin()); + assert(i4 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp new file mode 100644 index 00000000000000..25d4f4af19608b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(const key_type& k); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template > +void test() { + using M = std::flat_set; + + auto make = [](std::initializer_list il) { + M m; + for (int i : il) { + m.emplace(i); + } + return m; + }; + M m = make({1, 2, 3, 4, 5, 6, 7, 8}); + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(9); + assert(n == 0); + assert(m == make({1, 2, 3, 4, 5, 6, 7, 8})); + n = m.erase(4); + assert(n == 1); + assert(m == make({1, 2, 3, 5, 6, 7, 8})); + n = m.erase(1); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7, 8})); + n = m.erase(8); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7})); + n = m.erase(3); + assert(n == 1); + assert(m == make({2, 5, 6, 7})); + n = m.erase(4); + assert(n == 0); + assert(m == make({2, 5, 6, 7})); + n = m.erase(6); + assert(n == 1); + assert(m == make({2, 5, 7})); + n = m.erase(7); + assert(n == 1); + assert(m == make({2, 5})); + n = m.erase(2); + assert(n == 1); + assert(m == make({5})); + n = m.erase(5); + assert(n == 1); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test, std::greater<>>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp new file mode 100644 index 00000000000000..cbf7cac603806d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(K&& k); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanErase = requires(M m, Transparent k) { m.erase(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanErase); +static_assert(!CanErase); +static_assert(!CanErase); +static_assert(!CanErase); + +template +struct HeterogeneousKey { + explicit HeterogeneousKey(Key key, It it) : key_(key), it_(it) {} + operator It() && { return it_; } + auto operator<=>(Key key) const { return key_ <=> key; } + friend bool operator<(const HeterogeneousKey&, const HeterogeneousKey&) { + assert(false); + return false; + } + Key key_; + It it_; +}; + +template +void test_simple() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(3); // erase(K&&) [with K=int] + assert(n == 1); + assert((m == M{1, 2, 4})); + typename M::key_type lvalue = 2; + n = m.erase(lvalue); // erase(K&&) [with K=int&] + assert(n == 1); + assert((m == M{1, 4})); + const typename M::key_type const_lvalue = 1; + n = m.erase(const_lvalue); // erase(const key_type&) + assert(n == 1); + assert((m == M{4})); +} + +template +void test_transparent_comparator() { + using M = std::flat_set; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.erase(Transparent{"abc"})), typename M::size_type); + + auto n = m.erase(Transparent{"epsilon"}); + assert(n == 1); + + M expected = {"alpha", "beta", "eta", "gamma"}; + assert(m == expected); + + auto n2 = m.erase(Transparent{"aaa"}); + assert(n2 == 0); + assert(m == expected); +} + +int main(int, char**) { + test_simple>(); + test_simple>(); + test_simple>(); + test_simple>>(); + + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>>(); + + { + // P2077's HeterogeneousKey example + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.erase(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp new file mode 100644 index 00000000000000..c3bbffabb90a08 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// containers extract() &&; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanExtract = requires(T&& t) { std::forward(t).extract(); }; + +static_assert(CanExtract&&>); +static_assert(!CanExtract&>); +static_assert(!CanExtract const&>); +static_assert(!CanExtract const&&>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + M m = M({1, 2, 3}); + + std::same_as auto keys = std::move(m).extract(); + + auto expected_keys = {1, 2, 3}; + assert(std::ranges::equal(keys, expected_keys)); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // extracted object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m = M({1, 2, 3}); + std::same_as auto keys = std::move(m).extract(); + assert(keys.size() == 3); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); + } + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + auto c = std::move(m).extract(); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we try to erase the key after value emplacement failure. + // and after erasure failure, we clear the flat_set + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp new file mode 100644 index 00000000000000..c0ddadc3006987 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair insert(const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using VT = typename M::value_type; + M m; + + const VT v1(2); + std::same_as decltype(auto) r = m.insert(v1); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + + const VT v2(1); + r = m.insert(v2); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == 1); + + const VT v3(3); + r = m.insert(v3); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); + + const VT v4(3); + r = m.insert(v4); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp new file mode 100644 index 00000000000000..7381514a70eabb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; + + M m = {1,1,1,3,3,3}; + m.insert({ + 4, + 4, + 4, + 1, + 1, + 1, + 2, + 2, + 2, + }); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(*m.begin() == V(1)); + assert(*std::next(m.begin()) == V(2)); + assert(*std::next(m.begin(), 2) == V(3)); + assert(*std::next(m.begin(), 3) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp new file mode 100644 index 00000000000000..c343d53a62215a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator insert(const_iterator position, const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = typename M::iterator; + using VT = typename M::value_type; + + M m; + const VT v1(2); + std::same_as decltype(auto) r = m.insert(m.end(), v1); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + + const VT v2(1); + r = m.insert(m.end(), v2); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == 1); + + const VT v3(3); + r = m.insert(m.end(), v3); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); + + const VT v4(3); + r = m.insert(m.end(), v4); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp new file mode 100644 index 00000000000000..d20a8ef8fdd92d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + + int ar1[] = { + 2, + 2, + 2, + 1, + 1, + 1, + 3, + 3, + 3, + }; + int ar2[] = { + 4, + 4, + 4, + 1, + 1, + 1, + 0, + 0, + 0, + }; + + M m; + m.insert(cpp17_input_iterator(ar1), cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(cpp17_input_iterator(ar2), cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp new file mode 100644 index 00000000000000..84b6c7fc1d34f6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// +// iterator insert(const_iterator position, value_type&&); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "../helpers.h" +#include "test_macros.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + using R = typename M::iterator; + M m; + std::same_as decltype(auto) r = m.insert(m.end(), V(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == V(2)); + + r = m.insert(m.end(), V(1)); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == V(1)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp new file mode 100644 index 00000000000000..536307252c6405 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// void insert_range(R&& rg); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "MoveOnly.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint container-compatible-range +template +concept CanInsertRange = requires(M m, R&& r) { m.insert_range(std::forward(r)); }; + +using Set = std::flat_set; + +static_assert(CanInsertRange>); +static_assert(CanInsertRange>); +static_assert(!CanInsertRange*>>); +static_assert(!CanInsertRange*>>); + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using M = std::flat_set, KeyContainer>; + using It = forward_iterator; + M m = {10, 8, 5, 2, 1}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), It(ar + 6)}; + static_assert(std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9, 10})); + } + { + using M = std::flat_set, KeyContainer>; + using It = cpp20_input_iterator; + M m = {8, 5, 3, 2}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), sentinel_wrapper(It(ar + 6))}; + static_assert(!std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9})); + } + { + // The "uniquing" part uses the comparator, not operator==. + struct ModTen { + bool operator()(int a, int b) const { return (a % 10) < (b % 10); } + }; + using M = std::flat_set; + M m = {21, 43, 15, 37}; + int ar[] = {33, 18, 55, 18, 42}; + m.insert_range(ar); + assert((m == M{21, 42, 43, 15, 37, 18})); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // Items are forwarded correctly from the input range (P2767). + MoveOnly a[] = {3, 1, 4, 1, 5}; + std::flat_set m; + m.insert_range(a | std::views::as_rvalue); + MoveOnly expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + // The element type of the range doesn't need to be std::pair (P2767). + int pa[] = {3, 1, 4, 1, 5}; + std::deque> a(pa, pa + 5); + std::flat_set m; + m.insert_range(a); + int expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp new file mode 100644 index 00000000000000..7d95f0521eb1f6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// pair insert( value_type&& v); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + using R = std::pair; + using V = typename M::value_type; + + M m; + std::same_as decltype(auto) r = m.insert(V(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == V(2)); + + r = m.insert(V(1)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == V(1)); + + r = m.insert(V(3)); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); + + r = m.insert(V(3)); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp new file mode 100644 index 00000000000000..fa5bf86830daec --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(sorted_unique_t, initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + M m = {1, 1, 1, 3, 3, 3}; + m.insert(std::sorted_unique, {0, 1, 2, 4}); + assert(m.size() == 5); + assert(std::distance(m.begin(), m.end()) == 5); + assert(*m.begin() == V(0)); + assert(*std::next(m.begin()) == V(1)); + assert(*std::next(m.begin(), 2) == V(2)); + assert(*std::next(m.begin(), 3) == V(3)); + assert(*std::next(m.begin(), 4) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp new file mode 100644 index 00000000000000..ef7b8391cee33c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(sorted_unique_t, InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + int ar1[] = {1, 2, 3}; + + int ar2[] = {0, 2, 4}; + + M m; + m.insert(std::sorted_unique, + cpp17_input_iterator(ar1), + cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(std::sorted_unique, + cpp17_input_iterator(ar2), + cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp new file mode 100644 index 00000000000000..72d7261a182547 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -0,0 +1,169 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair insert(P&& x); +// template iterator insert(const_iterator hint, P&& x); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// Constraints: is_constructible_v is true. +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; +using Iter = Set::const_iterator; + +static_assert(CanInsert); +static_assert(CanInsert); +static_assert(!CanInsert); +static_assert(!CanInsert); + +static int expensive_comparisons = 0; +static int cheap_comparisons = 0; + +struct CompareCounter { + int i_ = 0; + CompareCounter(int i) : i_(i) {} + friend auto operator<=>(const CompareCounter& x, const CompareCounter& y) { + expensive_comparisons += 1; + return x.i_ <=> y.i_; + } + bool operator==(const CompareCounter&) const = default; + friend auto operator<=>(const CompareCounter& x, int y) { + cheap_comparisons += 1; + return x.i_ <=> y; + } +}; + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + const int expected[] = {1, 2, 3, 4, 5}; + { + // insert(P&&) + // Unlike flat_set, here we can't use key_compare to compare value_type versus P, + // so we must eagerly convert to value_type. + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, P&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // insert(value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens last + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // emplace(Args&&...) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.emplace(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // no ambiguity between insert(pos, P&&) and insert(first, last) + using M = std::flat_set; + struct Evil { + operator M::value_type() const; + operator M::const_iterator() const; + }; + std::flat_set m; + ASSERT_SAME_TYPE(decltype(m.insert(Evil())), std::pair); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); + } + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(t); + }; + test_emplace_exception_guarantee(insert_func); + } + { + auto insert_func_iter = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(m.begin(), t); + }; + test_emplace_exception_guarantee(insert_func_iter); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp new file mode 100644 index 00000000000000..49cb6eb6163c90 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void replace(container_type&& key_cont); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanReplace = requires(T t, Args&&... args) { t.replace(std::forward(args)...); }; + +using Set = std::flat_set; +static_assert(CanReplace>); +static_assert(!CanReplace&>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = M({1, 2, 3}); + KeyContainer new_keys = {7, 8}; + auto expected_keys = new_keys; + m.replace(std::move(new_keys)); + assert(m.size() == 2); + assert(std::ranges::equal(m, expected_keys)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp new file mode 100644 index 00000000000000..23a2dc85989bb7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// `check_assertion.h` requires Unix headers and regex support. +// REQUIRES: has-unix-headers +// UNSUPPORTED: no-localization +// UNSUPPORTED: no-exceptions + +// + +// void swap(flat_set& y) noexcept; +// friend void swap(flat_set& x, flat_set& y) noexcept + +// Test that std::terminate is called if any exception is thrown during swap + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../helpers.h" +#include "check_assertion.h" + +template +void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) { + { + // key swap throws + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m1, m2; + m1.emplace(1); + m1.emplace(2); + m2.emplace(3); + m2.emplace(4); + // swap is noexcept + EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); }); + } +} + +int main(int, char**) { + { + auto swap_func = [](auto& m1, auto& m2) { swap(m1, m2); }; + test_swap_exception_guarantee(swap_func); + } + + { + auto swap_func = [](auto& m1, auto& m2) { m1.swap(m2); }; + test_swap_exception_guarantee(swap_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp new file mode 100644 index 00000000000000..bc7baa67e52a59 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend void swap(flat_set& x, flat_set& y) noexcept + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptAdlSwap = requires(T t1, T t2) { + { swap(t1, t2) } noexcept; +}; + +static_assert(NoExceptAdlSwap>); + +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptAdlSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp new file mode 100644 index 00000000000000..b0b06a9499efc7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void swap(flat_set& y) noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptMemberSwap = requires(T t1, T t2) { + { t1.swap(t2) } noexcept; +}; + +static_assert(NoExceptMemberSwap>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptMemberSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp new file mode 100644 index 00000000000000..971b5e1c338dd1 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// key_compare key_comp() const; +// value_compare value_comp() const; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + { + using M = std::flat_set; + using Comp = std::less; // the default + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + { + using Comp = std::function; + using M = std::flat_set; + Comp comp = std::greater(); + M m({}, comp); + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(!kc(1, 2)); + assert(kc(2, 1)); + auto vc = m.value_comp(); + assert(!vc(1, 2)); + assert(vc(2, 1)); + } + { + using Comp = std::less<>; + using M = std::flat_set; + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + auto a = std::make_pair(1, 2); + ASSERT_SAME_TYPE(decltype(vc(a, a)), bool); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp new file mode 100644 index 00000000000000..b14da66f611301 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// bool contains(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp new file mode 100644 index 00000000000000..507560608952b0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template bool contains(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanContains = requires(M m, Transparent k) { m.contains(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanContains); +static_assert(CanContains); +static_assert(!CanContains); +static_assert(!CanContains); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.contains(Transparent{"abc"})), bool); + ASSERT_SAME_TYPE(decltype(std::as_const(m).contains(Transparent{"b"})), bool); + assert(m.contains(Transparent{"alpha"}) == true); + assert(m.contains(Transparent{"beta"}) == true); + assert(m.contains(Transparent{"epsilon"}) == true); + assert(m.contains(Transparent{"eta"}) == true); + assert(m.contains(Transparent{"gamma"}) == true); + assert(m.contains(Transparent{"al"}) == false); + assert(m.contains(Transparent{""}) == false); + assert(m.contains(Transparent{"g"}) == false); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto b = m.contains(Transparent{3}); + assert(b); + assert(transparent_used); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp new file mode 100644 index 00000000000000..478f615358b606 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type count(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using S = typename KeyContainer::size_type; + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp new file mode 100644 index 00000000000000..b591258f74399c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template size_type count(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanCount = requires(M m, Transparent k) { m.count(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanCount); +static_assert(CanCount); +static_assert(!CanCount); +static_assert(!CanCount); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.count(Transparent{"abc"})), typename M::size_type); + ASSERT_SAME_TYPE(decltype(std::as_const(m).count(Transparent{"b"})), typename M::size_type); + assert(m.count(Transparent{"alpha"}) == 1); + assert(m.count(Transparent{"beta"}) == 1); + assert(m.count(Transparent{"epsilon"}) == 1); + assert(m.count(Transparent{"eta"}) == 1); + assert(m.count(Transparent{"gamma"}) == 1); + assert(m.count(Transparent{"al"}) == 0); + assert(m.count(Transparent{""}) == 0); + assert(m.count(Transparent{"g"}) == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.count(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp new file mode 100644 index 00000000000000..a088b7fee17d2c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair equal_range(const key_type& k); +// pair equal_range(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin, begin)); + assert(m.equal_range(1) == std::pair(begin, begin + 1)); + assert(m.equal_range(2) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(3) == std::pair(begin + 2, begin + 2)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(6) == std::pair(begin + 4, begin + 4)); + assert(m.equal_range(7) == std::pair(begin + 4, begin + 4)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin() + 4, m.cbegin() + 5)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin() + 5, m.cbegin() + 5)); + } + + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin + 5, begin + 5)); + assert(m.equal_range(1) == std::pair(begin + 4, begin + 5)); + assert(m.equal_range(2) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(3) == std::pair(begin + 3, begin + 3)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(6) == std::pair(begin + 1, begin + 1)); + assert(m.equal_range(7) == std::pair(begin + 1, begin + 1)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin(), m.cbegin() + 1)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin(), m.cbegin())); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp new file mode 100644 index 00000000000000..ede5d91e19b9fd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair equal_range(const K& x); +// template pair equal_range(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanEqualRange = requires(M m, Transparent k) { m.equal_range(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanEqualRange); +static_assert(CanEqualRange); +static_assert(!CanEqualRange); +static_assert(!CanEqualRange); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + using R = std::pair; + using CR = std::pair; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.equal_range(Transparent{"abc"})), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(Transparent{"b"})), CR); + + auto test_found = [&](auto&& map, const std::string& expected_key) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(last - first == 1); + assert(*first == expected_key); + }; + + auto test_not_found = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(first == last); + assert(first - m.begin() == expected_offset); + }; + + test_found(m, "alpha"); + test_found(m, "beta"); + test_found(m, "epsilon"); + test_found(m, "eta"); + test_found(m, "gamma"); + test_found(cm, "alpha"); + test_found(cm, "beta"); + test_found(cm, "epsilon"); + test_found(cm, "eta"); + test_found(cm, "gamma"); + + test_not_found(m, "charlie", 2); + test_not_found(m, "aaa", 0); + test_not_found(m, "zzz", 5); + test_not_found(cm, "charlie", 2); + test_not_found(cm, "aaa", 0); + test_not_found(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto p = m.equal_range(Transparent{3}); + assert(p.first != p.second); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp new file mode 100644 index 00000000000000..cf0dd2d1dd831c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator find(const key_type& k); +// const_iterator find(const key_type& k) const; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.find(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(0)), typename M::const_iterator); + assert(m.find(0) == m.end()); + assert(m.find(1) == m.begin()); + assert(m.find(2) == m.begin() + 1); + assert(m.find(3) == m.end()); + assert(m.find(4) == m.begin() + 2); + assert(m.find(5) == m.begin() + 3); + assert(m.find(6) == m.end()); + assert(m.find(7) == m.end()); + assert(std::as_const(m).find(8) == m.begin() + 4); + assert(std::as_const(m).find(9) == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp new file mode 100644 index 00000000000000..730a57b0a6cb85 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator find(const K& x); +// template const_iterator find(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanFind = requires(M m, Transparent k) { m.find(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanFind); +static_assert(CanFind); +static_assert(!CanFind); +static_assert(!CanFind); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.find(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(Transparent{"b"})), typename M::const_iterator); + + auto test_find = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.find(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_find(m, "alpha", 0); + test_find(m, "beta", 1); + test_find(m, "epsilon", 2); + test_find(m, "eta", 3); + test_find(m, "gamma", 4); + test_find(m, "charlie", 5); + test_find(m, "aaa", 5); + test_find(m, "zzz", 5); + test_find(cm, "alpha", 0); + test_find(cm, "beta", 1); + test_find(cm, "epsilon", 2); + test_find(cm, "eta", 3); + test_find(cm, "gamma", 4); + test_find(cm, "charlie", 5); + test_find(cm, "aaa", 5); + test_find(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.find(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp new file mode 100644 index 00000000000000..093c32e537ed35 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator lower_bound(const key_type& k); +// const_iterator lower_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.begin()); + assert(m.lower_bound(1) == m.begin()); + assert(m.lower_bound(2) == m.begin() + 1); + assert(m.lower_bound(3) == m.begin() + 2); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 3); + assert(m.lower_bound(6) == m.begin() + 4); + assert(m.lower_bound(7) == m.begin() + 4); + assert(std::as_const(m).lower_bound(8) == m.begin() + 4); + assert(std::as_const(m).lower_bound(9) == m.end()); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.end()); + assert(m.lower_bound(1) == m.begin() + 4); + assert(m.lower_bound(2) == m.begin() + 3); + assert(m.lower_bound(3) == m.begin() + 3); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 1); + assert(m.lower_bound(6) == m.begin() + 1); + assert(m.lower_bound(7) == m.begin() + 1); + assert(std::as_const(m).lower_bound(8) == m.begin()); + assert(std::as_const(m).lower_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp new file mode 100644 index 00000000000000..18f9bc6dd32955 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator lower_bound(const K& x); +// template const_iterator lower_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanLowerBound = requires(M m, Transparent k) { m.lower_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanLowerBound); +static_assert(CanLowerBound); +static_assert(!CanLowerBound); +static_assert(!CanLowerBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_lower_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.lower_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_lower_bound(m, "abc", 0); + test_lower_bound(m, "alpha", 0); + test_lower_bound(m, "beta", 1); + test_lower_bound(m, "bets", 2); + test_lower_bound(m, "charlie", 2); + test_lower_bound(m, "echo", 2); + test_lower_bound(m, "epsilon", 2); + test_lower_bound(m, "eta", 3); + test_lower_bound(m, "gamma", 4); + test_lower_bound(m, "golf", 5); + test_lower_bound(m, "zzz", 5); + + test_lower_bound(cm, "abc", 0); + test_lower_bound(cm, "alpha", 0); + test_lower_bound(cm, "beta", 1); + test_lower_bound(cm, "bets", 2); + test_lower_bound(cm, "charlie", 2); + test_lower_bound(cm, "echo", 2); + test_lower_bound(cm, "epsilon", 2); + test_lower_bound(cm, "eta", 3); + test_lower_bound(cm, "gamma", 4); + test_lower_bound(cm, "golf", 5); + test_lower_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.lower_bound(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp new file mode 100644 index 00000000000000..ab34de85103175 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator upper_bound(const key_type& k); +// const_iterator upper_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.begin()); + assert(m.upper_bound(1) == m.begin() + 1); + assert(m.upper_bound(2) == m.begin() + 2); + assert(m.upper_bound(3) == m.begin() + 2); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 4); + assert(m.upper_bound(6) == m.begin() + 4); + assert(std::as_const(m).upper_bound(7) == m.begin() + 4); + assert(std::as_const(m).upper_bound(8) == m.end()); + assert(std::as_const(m).upper_bound(9) == m.end()); + } + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.end()); + assert(m.upper_bound(1) == m.end()); + assert(m.upper_bound(2) == m.begin() + 4); + assert(m.upper_bound(3) == m.begin() + 3); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 2); + assert(m.upper_bound(6) == m.begin() + 1); + assert(m.upper_bound(7) == m.begin() + 1); + assert(std::as_const(m).upper_bound(8) == m.begin() + 1); + assert(std::as_const(m).upper_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp new file mode 100644 index 00000000000000..69ce2ae926a305 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator upper_bound(const K& x); +// template const_iterator upper_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanUpperBound = requires(M m, Transparent k) { m.upper_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanUpperBound); +static_assert(CanUpperBound); +static_assert(!CanUpperBound); +static_assert(!CanUpperBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_upper_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.upper_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_upper_bound(m, "abc", 0); + test_upper_bound(m, "alpha", 1); + test_upper_bound(m, "beta", 2); + test_upper_bound(m, "bets", 2); + test_upper_bound(m, "charlie", 2); + test_upper_bound(m, "echo", 2); + test_upper_bound(m, "epsilon", 3); + test_upper_bound(m, "eta", 4); + test_upper_bound(m, "gamma", 5); + test_upper_bound(m, "golf", 5); + test_upper_bound(m, "zzz", 5); + + test_upper_bound(cm, "abc", 0); + test_upper_bound(cm, "alpha", 1); + test_upper_bound(cm, "beta", 2); + test_upper_bound(cm, "bets", 2); + test_upper_bound(cm, "charlie", 2); + test_upper_bound(cm, "echo", 2); + test_upper_bound(cm, "epsilon", 3); + test_upper_bound(cm, "eta", 4); + test_upper_bound(cm, "gamma", 5); + test_upper_bound(cm, "golf", 5); + test_upper_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.upper_bound(Transparent{2}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h new file mode 100644 index 00000000000000..9fff262d84234e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -0,0 +1,294 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_flat_set_HELPERS_H +#define SUPPORT_flat_set_HELPERS_H + +#include +#include +#include +#include +#include + +#include "test_allocator.h" +#include "test_macros.h" + +template +void check_invariant(const std::flat_set& m) { + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); + auto key_equal = [&](const auto& x, const auto& y) { + const auto& c = m.key_comp(); + return !c(x, y) && !c(y, x); + }; + assert(std::adjacent_find(m.begin(), m.end(), key_equal) == m.end()); +} + +struct StartsWith { + explicit StartsWith(char ch) : lower_(1, ch), upper_(1, ch + 1) {} + StartsWith(const StartsWith&) = delete; + void operator=(const StartsWith&) = delete; + struct Less { + using is_transparent = void; + bool operator()(const std::string& a, const std::string& b) const { return a < b; } + bool operator()(const StartsWith& a, const std::string& b) const { return a.upper_ <= b; } + bool operator()(const std::string& a, const StartsWith& b) const { return a < b.lower_; } + bool operator()(const StartsWith&, const StartsWith&) const { + assert(false); // should not be called + return false; + } + }; + +private: + std::string lower_; + std::string upper_; +}; + +template +struct CopyOnlyVector : std::vector { + using std::vector::vector; + + CopyOnlyVector(const CopyOnlyVector&) = default; + CopyOnlyVector(CopyOnlyVector&& other) : CopyOnlyVector(other) {} + CopyOnlyVector(CopyOnlyVector&& other, std::vector::allocator_type alloc) : CopyOnlyVector(other, alloc) {} + + CopyOnlyVector& operator=(const CopyOnlyVector&) = default; + CopyOnlyVector& operator=(CopyOnlyVector& other) { return this->operator=(other); } +}; + +template +struct Transparent { + T t; + + operator T() const + requires ConvertibleToT + { + return t; + } +}; + +template +using ConvertibleTransparent = Transparent; + +template +using NonConvertibleTransparent = Transparent; + +struct TransparentComparator { + using is_transparent = void; + + bool* transparent_used = nullptr; + TransparentComparator() = default; + TransparentComparator(bool& used) : transparent_used(&used) {} + + template + bool operator()(const T& t, const Transparent& transparent) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return t < transparent.t; + } + + template + bool operator()(const Transparent& transparent, const T& t) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return transparent.t < t; + } + + template + bool operator()(const T& t1, const T& t2) const { + return t1 < t2; + } +}; + +struct NonTransparentComparator { + template + bool operator()(const T&, const Transparent&) const; + + template + bool operator()(const Transparent&, const T&) const; + + template + bool operator()(const T&, const T&) const; +}; + +struct NoDefaultCtr { + NoDefaultCtr() = delete; +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +struct EmplaceUnsafeContainer : std::vector { + using std::vector::vector; + + template + auto emplace(Args&&... args) -> decltype(std::declval>().emplace(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } + + template + auto insert(Args&&... args) -> decltype(std::declval>().insert(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } +}; + +template +struct ThrowOnEraseContainer : std::vector { + using std::vector::vector; + + template + auto erase(Args&&... args) -> decltype(std::declval>().erase(std::forward(args)...)) { + throw 42; + } +}; + +template +struct ThrowOnMoveContainer : std::vector { + using std::vector::vector; + + ThrowOnMoveContainer(ThrowOnMoveContainer&&) { throw 42; } + + ThrowOnMoveContainer& operator=(ThrowOnMoveContainer&&) { throw 42; } +}; + +#endif + +template +void test_emplace_exception_guarantee([[maybe_unused]] F&& emplace_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using C = TransparentComparator; + { + // Throw on emplace the key, and underlying has strong exception guarantee + using KeyContainer = std::vector>; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + + test_allocator_statistics stats; + + KeyContainer a({1, 2, 3, 4}, test_allocator{&stats}); + [[maybe_unused]] auto expected_keys = a; + M m(std::sorted_unique, std::move(a)); + + stats.throw_after = 1; + try { + emplace_function(m, 0); + assert(false); + } catch (const std::bad_alloc&) { + check_invariant(m); + // In libc++, the flat_set is unchanged + LIBCPP_ASSERT(m.size() == 4); + LIBCPP_ASSERT(std::ranges::equal(m, expected_keys)); + } + } + { + // Throw on emplace the key, and underlying has no strong exception guarantee + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(!std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + KeyContainer a = {1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + emplace_function(m, 0); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, the flat_set is cleared + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} + +template +void test_insert_range_exception_guarantee([[maybe_unused]] F&& insert_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + test_allocator_statistics stats; + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + + std::vector newValues = {0, 1, 5, 6, 7, 8}; + stats.throw_after = 1; + try { + insert_function(m, newValues); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when inserting a range + LIBCPP_ASSERT(m.size() == 0); + } +#endif +} + +template +void test_erase_exception_guarantee([[maybe_unused]] F&& erase_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + { + // key erase throws + using KeyContainer = ThrowOnEraseContainer; + using M = std::flat_set; + + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + erase_function(m, 3); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when erasing + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} +class Moveable { + int int_; + double double_; + +public: + Moveable() : int_(0), double_(0) {} + Moveable(int i, double d) : int_(i), double_(d) {} + Moveable(Moveable&& x) : int_(x.int_), double_(x.double_) { + x.int_ = -1; + x.double_ = -1; + } + Moveable& operator=(Moveable&& x) { + int_ = x.int_; + x.int_ = -1; + double_ = x.double_; + x.double_ = -1; + return *this; + } + + Moveable(const Moveable&) = delete; + Moveable& operator=(const Moveable&) = delete; + bool operator==(const Moveable& x) const { return int_ == x.int_ && double_ == x.double_; } + bool operator<(const Moveable& x) const { return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_); } + + int get() const { return int_; } + bool moved() const { return int_ == -1; } +}; + +#endif // SUPPORT_flat_set_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp new file mode 100644 index 00000000000000..c4a9810016536b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Check that std::flat_set and its iterators can be instantiated with an incomplete +// type. + +#include +#include + +struct A { + using Set = std::flat_set; + int data; + Set m; + Set::iterator it; + Set::const_iterator cit; +}; + +// Implement the operator< required in order to instantiate flat_set +bool operator<(A const& L, A const& R) { return L.data < R.data; } + +int main(int, char**) { + A a; + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp new file mode 100644 index 00000000000000..f6d08bb736d300 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend bool operator==(const flat_set& x, const flat_set& y); +// friend synth-three-way-result +// operator<=>(const flat_set& x, const flat_set& y); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_comparisons.h" +#include "test_container_comparisons.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, true)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } + { + // Comparisons use value_type's native operators, not the comparator + using C = std::flat_set>; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, false)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = C(std::sorted_unique, {std::numeric_limits::quiet_NaN()}); + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + } + { + // Comparisons use value_type's native operators, not the comparator + struct StrongComp { + bool operator()(double a, double b) const { return std::strong_order(a, b) < 0; } + }; + using C = std::flat_set; + C s1 = {1}; + C s2 = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + s1 = {1, std::numeric_limits::quiet_NaN(), 1}; + s2 = {std::numeric_limits::quiet_NaN(), 1}; + assert(std::lexicographical_compare_three_way(s1.begin(), s1.end(), s2.begin(), s2.end(), std::strong_order) == + std::strong_ordering::equal); + assert(s1 != s2); + assert((s1 <=> s2) == std::partial_ordering::unordered); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp new file mode 100644 index 00000000000000..a845b2b81e89d3 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// using key_type = Key; +// using value_type = Key; +// using key_compare = Compare; +// using value_compare = Compare; +// using reference = value_type&; +// using const_reference = const value_type&; +// using size_type = typename KeyContainer::size_type; +// using difference_type = typename KeyContainer::difference_type; +// using iterator = implementation-defined; // see [container.requirements] +// using const_iterator = implementation-defined; // see [container.requirements] +// using reverse_iterator = std::reverse_iterator; +// using const_reverse_iterator = std::reverse_iterator; +// using container_type = KeyContainer; + +#include +#include +#include +#include +#include +#include +#include +#include "min_allocator.h" + +void test() { + { + using M = std::flat_set; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(requires { typename M::value_compare; }); + } + + { + struct A {}; + struct Compare { + bool operator()(const std::string&, const std::string&) const; + }; + using M = std::flat_set>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + } + { + using C = std::flat_set, std::deque>>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + // size_type is invariably size_t + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>>); + } +} >From 96903d9c8f1ea42de65fbe1a07e59413a1630d1e Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 13:21:24 +0000 Subject: [PATCH 2/5] review --- libcxx/include/__flat_set/flat_set.h | 137 +++---- .../flat.set/flat.set.capacity/empty.pass.cpp | 14 +- .../flat.set.capacity/max_size.pass.cpp | 8 +- .../flat.set/flat.set.capacity/size.pass.cpp | 14 +- .../flat.set/flat.set.cons/alloc.pass.cpp | 6 +- .../assign_initializer_list.pass.cpp | 19 +- .../flat.set/flat.set.cons/compare.pass.cpp | 6 +- .../flat.set.cons/containers.pass.cpp | 25 +- .../flat.set/flat.set.cons/copy.pass.cpp | 6 +- .../flat.set.cons/copy_alloc.pass.cpp | 6 +- .../copy_assign.addressof.compile.pass.cpp | 30 -- .../flat.set.cons/copy_assign.pass.cpp | 17 +- .../flat.set/flat.set.cons/deduct.pass.cpp | 353 +++++++++--------- .../flat.set/flat.set.cons/default.pass.cpp | 36 +- .../flat.set.cons/default_noexcept.pass.cpp | 58 --- .../flat.set.cons/dtor_noexcept.pass.cpp | 6 +- .../flat.set.cons/initializer_list.pass.cpp | 6 +- .../flat.set/flat.set.cons/iter_iter.pass.cpp | 6 +- .../flat.set/flat.set.cons/move.pass.cpp | 107 +++++- .../flat.set.cons/move_alloc.pass.cpp | 10 +- .../flat.set.cons/move_assign.pass.cpp | 141 ++++++- .../flat.set.cons/move_assign_clears.pass.cpp | 101 ----- .../move_assign_noexcept.pass.cpp | 85 ----- .../flat.set.cons/move_exceptions.pass.cpp | 58 --- .../flat.set.cons/move_noexcept.pass.cpp | 94 ----- .../flat.set/flat.set.cons/pmr.pass.cpp | 6 +- .../flat.set/flat.set.cons/range.pass.cpp | 6 +- .../flat.set.cons/sorted_container.pass.cpp | 6 +- .../sorted_initializer_list.pass.cpp | 10 +- .../flat.set.cons/sorted_iter_iter.pass.cpp | 6 +- .../flat.set.erasure/erase_if.pass.cpp | 20 +- .../erase_if_exceptions.pass.cpp | 7 +- .../flat.set.iterators/iterator.pass.cpp | 18 +- .../iterator_comparison.pass.cpp | 14 +- .../reverse_iterator.pass.cpp | 8 +- .../flat.set.modifiers/clear.pass.cpp | 18 +- .../flat.set.modifiers/emplace.pass.cpp | 25 +- .../flat.set.modifiers/emplace_hint.pass.cpp | 25 +- .../flat.set.modifiers/erase_iter.pass.cpp | 25 +- .../erase_iter_iter.pass.cpp | 24 +- .../flat.set.modifiers/erase_key.pass.cpp | 37 +- .../erase_key_transparent.pass.cpp | 34 +- .../flat.set.modifiers/extract.pass.cpp | 21 +- .../flat.set.modifiers/insert_cv.pass.cpp | 33 +- .../insert_initializer_list.pass.cpp | 42 ++- .../insert_iter_cv.pass.cpp | 23 +- .../insert_iter_iter.pass.cpp | 27 +- .../insert_iter_rv.pass.cpp | 43 ++- .../flat.set.modifiers/insert_range.pass.cpp | 38 +- .../flat.set.modifiers/insert_rv.pass.cpp | 42 ++- .../insert_sorted_initializer_list.pass.cpp | 35 +- .../insert_sorted_iter_iter.pass.cpp | 29 +- .../insert_transparent.pass.cpp | 21 +- .../flat.set.modifiers/replace.pass.cpp | 50 +-- .../flat.set.modifiers/swap_free.pass.cpp | 16 +- .../flat.set.modifiers/swap_member.pass.cpp | 14 +- .../flat.set/flat.set.observers/comp.pass.cpp | 6 +- .../flat.set.operations/contains.pass.cpp | 14 +- .../contains_transparent.pass.cpp | 17 +- .../flat.set.operations/count.pass.cpp | 14 +- .../count_transparent.pass.cpp | 16 +- .../flat.set.operations/equal_range.pass.cpp | 14 +- .../equal_range_transparent.pass.cpp | 16 +- .../flat.set.operations/find.pass.cpp | 14 +- .../find_transparent.pass.cpp | 16 +- .../flat.set.operations/lower_bound.pass.cpp | 14 +- .../lower_bound_transparent.pass.cpp | 16 +- .../flat.set.operations/upper_bound.pass.cpp | 14 +- .../upper_bound_transparent.pass.cpp | 17 +- .../container.adaptors/flat.set/helpers.h | 19 +- .../flat.set/incomplete_type.pass.cpp | 5 +- .../flat.set/op_compare.pass.cpp | 17 +- 72 files changed, 1214 insertions(+), 1087 deletions(-) delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index c920632c453bf5..37e4c9f7c686b0 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP___FLAT_set_FLAT_SET_H -#define _LIBCPP___FLAT_set_FLAT_SET_H +#ifndef _LIBCPP___FLAT_SET_FLAT_SET_H +#define _LIBCPP___FLAT_SET_FLAT_SET_H #include <__algorithm/lexicographical_compare_three_way.h> #include <__algorithm/min.h> @@ -99,13 +99,6 @@ class flat_set { using const_reverse_iterator = std::reverse_iterator; using container_type = _KeyContainer; -private: - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = - uses_allocator::value; - - _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; - public: // [flat.set.cons], construct/copy/destroy _LIBCPP_HIDE_FROM_ABI @@ -178,31 +171,31 @@ class flat_set { : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( @@ -210,7 +203,7 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { @@ -219,12 +212,12 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) # if _LIBCPP_HAS_EXCEPTIONS try @@ -239,14 +232,14 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert(__first, __last); } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { @@ -254,7 +247,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { @@ -262,7 +255,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, @@ -274,37 +267,37 @@ class flat_set { } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert_range(std::forward<_Range>(__rg)); } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { insert_range(std::forward<_Range>(__rg)); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} @@ -334,11 +327,8 @@ class flat_set { // iterators _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } @@ -382,7 +372,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { return emplace(std::forward<_Kp>(__x)); } @@ -395,7 +385,7 @@ class flat_set { } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { return emplace_hint(__hint, std::forward<_Kp>(__x)); } @@ -425,7 +415,7 @@ class flat_set { __reserve(ranges::size(__range)); } - __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + __append_sort_merge_unique(std::forward<_Range>(__range)); } _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } @@ -468,7 +458,7 @@ class flat_set { } template - requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> && !is_convertible_v<_Kp &&, const_iterator>) _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { auto [__first, __last] = equal_range(__x); @@ -505,13 +495,13 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { return __find_impl(*this, __x); } @@ -519,7 +509,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { return contains(__x) ? 1 : 0; } @@ -527,7 +517,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { return find(__x) != end(); } @@ -541,13 +531,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { return ranges::lower_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { return ranges::lower_bound(__keys_, __x, __compare_); } @@ -561,13 +551,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { return ranges::upper_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { return ranges::upper_bound(__keys_, __x, __compare_); } @@ -581,12 +571,12 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { return __equal_range_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { return __equal_range_impl(*this, __x); } @@ -611,14 +601,14 @@ class flat_set { }; template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), __compare_(std::forward<_CompArg>(__comp)...) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc)), __compare_(std::forward<_CompArg>(__comp)...) {} @@ -637,17 +627,30 @@ class flat_set { __keys_.erase(__dup_start, __keys_.end()); } - template - _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { - auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); - size_type __old_size = size(); - if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { - __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + template + _LIBCPP_HIDE_FROM_ABI void __append(_InputIterator __first, _InputIterator __last) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append(_Range&& __rng) { + if constexpr (requires { __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); }) { + // C++23 Sequence Container should have insert_range member function + __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); + } else if constexpr (ranges::common_range<_Range>) { + __keys_.insert(__keys_.end(), ranges::begin(__rng), ranges::end(__rng)); } else { - for (; __first != __last; ++__first) { - __keys_.insert(__keys_.end(), *__first); + for (auto&& __x : __rng) { + __keys_.insert(__keys_.end(), std::forward(__x)); } } + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_Args&&... __args) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + __append(std::forward<_Args>(__args)...); if (size() != __old_size) { if constexpr (!_WasSorted) { ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); @@ -831,18 +834,18 @@ template struct uses_allocator, _Allocator> : bool_constant> {}; - template - _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type - erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { - auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); - auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { - return static_cast(__pred(e)); - }); - auto __res = __flat_set.__keys_.end() - __it; - __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); - __guard.__complete(); - return __res; - } +template +_LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type +erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; +} _LIBCPP_END_NAMESPACE_STD @@ -850,4 +853,4 @@ _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS -#endif // _LIBCPP___FLAT_set_FLAT_SET_H +#endif // _LIBCPP___FLAT_SET_FLAT_SET_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp index 204df1d681af1b..223b92fc3e8e84 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m; @@ -38,11 +38,15 @@ void test() { assert(m.empty()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index cd7f424e00ece2..0489d886257911 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -24,7 +24,8 @@ #include "test_allocator.h" #include "test_macros.h" -int main(int, char**) { +void test() { + { using A1 = limited_allocator; using C = std::flat_set, std::vector>; @@ -59,5 +60,10 @@ int main(int, char**) { assert(c.max_size() <= max_dist); assert(c.max_size() <= alloc_max_size(std::allocator())); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp index 7c156e95ecb1c8..9f5ffdd0663513 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; using S = typename M::size_type; { @@ -56,11 +56,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp index acc0817d7cac4d..d14e883dd5e936 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -22,7 +22,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -55,6 +55,10 @@ int main(int, char**) { auto v = std::move(m).extract(); assert(v.get_allocator().get_id() == 5); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7f75f1e1611e3b..7e948d7c5fe976 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -33,7 +33,6 @@ void test() { m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); - LIBCPP_ASSERT(std::ranges::equal(m, expected)); } { M m = {10, 8}; @@ -44,13 +43,17 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp index b3bee18f5a936b..110757a1bb9ab6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -78,6 +78,10 @@ int main(int, char**) { auto keys = std::move(m).extract(); assert(keys.get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp index 3d1e6240c952e8..6b1246885bf527 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -36,7 +36,7 @@ void conversion_test(T); template concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -116,21 +116,16 @@ int main(int, char**) { auto m = M(ks, A(4)); // replaces the allocators assert(!ks.empty()); // it was an lvalue above assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); + auto keys = M(m).extract(); assert(keys.get_allocator() == A(4)); - } - { - // flat_set(container_type , const Allocator&) + // explicit(false) - using A = test_allocator; - using M = std::flat_set, std::deque>; static_assert(ImplicitlyConstructible&, const A&>); - auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); - M m = {ks, A(4)}; // implicit ctor - assert(!ks.empty()); // it was an lvalue above - assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); - assert(keys.get_allocator() == A(4)); + M m2 = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert(m2 == m); + auto keys2 = std::move(m).extract(); + assert(keys2.get_allocator() == A(4)); } { // flat_set(container_type , key_compare, const Allocator&) @@ -153,6 +148,10 @@ int main(int, char**) { keys = std::move(m2).extract(); assert(keys.get_allocator() == A(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp index f1dbc955e1b0de..1ba550d98f01f6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -21,7 +21,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; std::vector> ks({1, 3, 5}, test_allocator(6)); @@ -59,6 +59,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == other_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp index 59fb9d0a38366f..5011bd20030641 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -23,7 +23,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -58,6 +58,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == test_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp deleted file mode 100644 index 169b469f3bca68..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp +++ /dev/null @@ -1,30 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(const flat_set& s); - -// Validate whether the container can be copy-assigned (move-assigned, swapped) -// with an ADL-hijacking operator& - -#include -#include - -#include "test_macros.h" -#include "operator_hijacker.h" - -void test() { - std::flat_set so; - std::flat_set s; - s = so; - s = std::move(so); - swap(s, so); -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp index cdd5045f4bb9f7..695363e3aeabab 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -17,11 +17,12 @@ #include #include +#include "operator_hijacker.h" #include "test_macros.h" #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // test_allocator is not propagated using C = test_less; @@ -81,5 +82,19 @@ int main(int, char**) { m = static_cast(m); assert((m == M{{1, 2}})); } + { + // Validate whether the container can be copy-assigned (move-assigned, swapped) + // with an ADL-hijacking operator& + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); + } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp index 612e64a7c42f23..607fe0d1a9713a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -26,24 +26,21 @@ #include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" -using P = std::pair; -using PC = std::pair; - void test_copy() { { - std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set source = {1, 2}; std::flat_set s(source); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s{source}; // braces instead of parens ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s(source, std::allocator()); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); @@ -52,275 +49,259 @@ void test_copy() { void test_containers() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); - std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + int expected[] = {1, 2, 3, INT_MAX}; { - std::flat_set s(ks, vs); + std::flat_set s(ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + std::flat_set s(std::sorted_unique, sorted_ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, test_allocator(0, 44)); + std::flat_set s(ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_containers_compare() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); - std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + int expected[] = {INT_MAX, 3, 2, 1}; { - std::flat_set s(ks, vs, std::greater()); + std::flat_set s(ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_iter_iter() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const int arr[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arr[] = {1, 2, 3, INT_MAX}; + const int arrc[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arrc[] = {1, 2, 3, INT_MAX}; { std::flat_set m(std::begin(arr), std::end(arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::begin(arrc), std::end(arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.begin(), mo.end()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.cbegin(), mo.cend()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); - } - { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); + // This does not deduce to flat_set(InputIterator, InputIterator) + // But deduces to flat_set(initializer_list) + int source[3] = {1, 2, 3}; + std::flat_set s = {source, source + 3}; + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 2); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + int source[3] = {1, 2, 3}; std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); assert(s.size() == 3); } } void test_iter_iter_compare() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m(std::begin(arr), std::end(arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::begin(arrc), std::end(arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set mo; - std::flat_set m(mo.begin(), mo.end(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } - { - std::flat_set mo; - std::flat_set m(mo.cbegin(), mo.cend(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } + // const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m(std::begin(arr), std::end(arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.begin(), mo.end(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.cbegin(), mo.cend(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } } void test_initializer_list() { - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - { - std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - } - { - using M = std::flat_set; - M m; - std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - assert(s[m] == m); - } + // const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + // { + // std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // } + // { + // using M = std::flat_set; + // M m; + // std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // assert(s[m] == m); + // } } void test_initializer_list_compare() { - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } } void test_from_range() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; - { - std::flat_set s(std::from_range, r); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + // { + // std::flat_set s(std::from_range, r); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } void test_from_range_compare() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; - { - std::flat_set s(std::from_range, r, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + // { + // std::flat_set s(std::from_range, r, std::greater()); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } int main(int, char**) { @@ -335,7 +316,7 @@ int main(int, char**) { test_from_range(); test_from_range_compare(); - AssociativeContainerDeductionGuidesSfinaeAway>(); + AssociativeContainerDeductionGuidesSfinaeAway>(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp index 64b0bfcb383a72..292af96c61582f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -19,9 +19,10 @@ #include #include -#include "test_macros.h" #include "min_allocator.h" +#include "MoveOnly.h" #include "test_allocator.h" +#include "test_macros.h" struct DefaultCtableComp { explicit DefaultCtableComp() { default_constructed_ = true; } @@ -29,7 +30,12 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +void test() { { std::flat_set m; assert(m.empty()); @@ -60,6 +66,32 @@ int main(int, char**) { assert(m.key_comp().default_constructed_); } } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp deleted file mode 100644 index b4a3b6de205a31..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set() -// noexcept( -// is_nothrow_default_constructible_v && -// is_nothrow_default_constructible_v); - -// This tests a conforming extension - -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -struct ThrowingCtorComp { - ThrowingCtorComp() noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -int main(int, char**) { -#if defined(_LIBCPP_VERSION) - { - using C = std::flat_set; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set, std::vector>>; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } -#endif // _LIBCPP_VERSION - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp index c0d315c0ce74b4..fa1e2478af4599 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -27,7 +27,7 @@ struct ThrowingDtorComp { ~ThrowingDtorComp() noexcept(false) {} }; -int main(int, char**) { +void test() { { using C = std::flat_set; static_assert(std::is_nothrow_destructible_v); @@ -52,6 +52,10 @@ int main(int, char**) { C c; } #endif // _LIBCPP_VERSION +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp index cd2319e91f760d..9aed5c88ee7268 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -35,7 +35,7 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -146,6 +146,10 @@ int main(int, char**) { M m({5, 2, 2, 3, 1, 3}, {}, a); assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp index 65eebc21a66c4c..2d0b07c9155fdb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -29,7 +29,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -131,6 +131,10 @@ int main(int, char**) { LIBCPP_ASSERT(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp index 69b340ad09fe15..b2853844b986c6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -25,7 +25,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; using A = test_allocator; @@ -79,5 +79,110 @@ int main(int, char**) { LIBCPP_ASSERT(m1.empty()); LIBCPP_ASSERT(m1.size() == 0); } +} + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +void test_move_noexcept() { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +} + +#if !defined(TEST_HAS_NO_EXCEPTIONS) +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +void test_move_exception() { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } +} +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + +int main(int, char**) { + test(); + test_move_noexcept(); +#if !defined(TEST_HAS_NO_EXCEPTIONS) + test_move_exception(); +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp index fc7f68d8c967ad..489b6ff36324b3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -53,7 +53,7 @@ int main(int, char**) { assert(m.size() == 3); auto keys = std::move(m).extract(); assert(keys.get_allocator() == A(3)); - assert(std::ranges::equal(keys, expected )); + assert(std::ranges::equal(keys, expected)); // The original flat_set is moved-from. assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); @@ -63,13 +63,17 @@ int main(int, char**) { } { // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, CopyOnlyVector>; + using M = std::flat_set, CopyOnlyVector>; M m1 = M({1, 2, 3}); M m2(std::move(m1), std::allocator{}); assert(m2.size() == 3); check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index b16dc38dd40285..e55a0516ed1bed 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -22,11 +22,144 @@ #include "test_macros.h" #include "MoveOnly.h" +#include "../helpers.h" #include "../../../test_compare.h" #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +void test_move_assign_clears() { + // Preserves the class invariant for the moved-from flat_set. + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } +} + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +void test_move_assign_no_except() { + // This tests a conforming extension + + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } +} + +void test() { { using C = test_less; using A1 = test_allocator; @@ -64,6 +197,12 @@ int main(int, char**) { assert(ks.get_allocator() == A()); assert(mo.empty()); } +} + +int main(int, char**) { + test(); + test_move_assign_clears(); + test_move_assign_no_except(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp deleted file mode 100644 index 50817f4be8a812..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&&); -// Preserves the class invariant for the moved-from flat_set. - -#include -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -struct MoveNegates { - int value_ = 0; - MoveNegates() = default; - MoveNegates(int v) : value_(v) {} - MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } - MoveNegates& operator=(MoveNegates&& rhs) { - value_ = rhs.value_; - rhs.value_ = -rhs.value_; - return *this; - } - ~MoveNegates() = default; - auto operator<=>(const MoveNegates&) const = default; -}; - -struct MoveClears { - int value_ = 0; - MoveClears() = default; - MoveClears(int v) : value_(v) {} - MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } - MoveClears& operator=(MoveClears&& rhs) { - value_ = rhs.value_; - rhs.value_ = 0; - return *this; - } - ~MoveClears() = default; - auto operator<=>(const MoveClears&) const = default; -}; - -int main(int, char**) { - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, std::vector>; - M m1 = M({1, 2, 3}); - M m2 = M({1, 2}); - m2 = std::move(m1); - assert(m2.size() == 3); - check_invariant(m1); - LIBCPP_ASSERT(m1.empty()); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp deleted file mode 100644 index 86f3568f0d67a6..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&& c) -// noexcept( -// is_nothrow_move_assignable::value && -// is_nothrow_move_assignable::value && -// is_nothrow_copy_assignable::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include - -#include "MoveOnly.h" -#include "test_allocator.h" -#include "test_macros.h" - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -struct MoveThrowsComp { - MoveThrowsComp(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp(const MoveThrowsComp&) noexcept(true); - MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); - bool operator()(const auto&, const auto&) const; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - // Test with a comparator that throws on move-assignment. - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); - } - { - // Test with a container that throws on move-assignment. - using C = std::flat_set, std::pmr::vector>; - static_assert(!std::is_nothrow_move_assignable_v); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp deleted file mode 100644 index 17e4e40387606c..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 -// UNSUPPORTED: no-exceptions - -// - -// flat_set(flat_set&& s); -// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. - -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -static int countdown = 0; - -struct EvilContainer : std::vector { - EvilContainer() = default; - EvilContainer(EvilContainer&& rhs) { - // Throw on move-construction. - if (--countdown == 0) { - rhs.insert(rhs.end(), 0); - rhs.insert(rhs.end(), 0); - throw 42; - } - } -}; - -int main(int, char**) { - { - using M = std::flat_set, EvilContainer>; - M mo = {1, 2, 3}; - countdown = 1; - try { - M m = std::move(mo); - assert(false); // not reached - } catch (int x) { - assert(x == 42); - } - // The source flat_set maintains its class invariant. - check_invariant(mo); - LIBCPP_ASSERT(mo.empty()); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp deleted file mode 100644 index 49d1151fd8a993..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set(flat_set&&) -// noexcept(is_nothrow_move_constructible::value && -// is_nothrow_move_constructible::value && -// is_nothrow_copy_constructible::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -template -struct ThrowingMoveAllocator { - using value_type = T; - explicit ThrowingMoveAllocator() = default; - ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; - ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} - T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } - void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } - friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; -}; - -struct ThrowingMoveComp { - ThrowingMoveComp() = default; - ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} - ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - { - using C = std::flat_set, std::deque>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#if _LIBCPP_VERSION - { - // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators - using C = std::flat_set, std::deque>>; - static_assert(!std::is_nothrow_move_constructible_v>>); - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#endif // _LIBCPP_VERSION - { - // Comparator fails to be nothrow-move-constructible - using C = std::flat_set; - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp index 785718d2eed333..1a4eafa8802918 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -28,7 +28,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // flat_set(const Allocator& a); using M = std::flat_set, std::pmr::vector>; @@ -317,6 +317,10 @@ int main(int, char**) { assert(vm[0].key_comp() == C(4)); assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp index bb9f99c228bfec..bd7b5c12432e96 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -56,7 +56,7 @@ static_assert( !std:: is_constructible_v>, std::less, std::allocator>); -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -168,6 +168,10 @@ int main(int, char**) { assert(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp index 2d442d49667bd0..873ff32b62936a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -138,6 +138,10 @@ int main(int, char**) { assert(m2 == m); assert(std::move(m2).extract().get_allocator() == A(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp index 01956a78c7f48d..a8dac35aefee81 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -33,10 +33,10 @@ template std::initializer_list il = {1, 2, 4, 5}; -const auto il1 = il; -const auto il2 = il; +void test() { + const auto il1 = il; + const auto il2 = il; -int main(int, char**) { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -145,6 +145,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp index b5229a84dd5133..b184ee9c3f5aba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -28,7 +28,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -151,6 +151,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp index 134db83aef3cad..806779bc7d16bc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -49,7 +49,7 @@ void test0( } template -void test() { +void test_one() { // Test all the plausible signatures for this predicate. auto is1 = [](typename S::const_reference v) { return v == 1; }; auto is2 = [](typename S::value_type v) { return v == 2; }; @@ -76,14 +76,18 @@ void test() { test0({1, 2, 3}, False, {1, 2, 3}, 0); } +void test() { + test_one>(); + test_one, std::vector>>>(); + test_one, std::vector>>>(); + test_one, std::deque>>>(); + test_one, std::deque>>>(); + test_one>(); + test_one>(); +} + int main(int, char**) { - test>(); - test, std::vector>>>(); - test, std::vector>>>(); - test, std::deque>>>(); - test, std::deque>>>(); - test>(); - test>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp index 6bbe1ad4f01670..37b4a40f0165cf 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -65,7 +65,7 @@ struct ErasurePredicate { bool operator()(const auto& x) const { return (3 <= x && x <= 5); } }; -int main(int, char**) { +void test() { const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; { using M = std::flat_set; @@ -124,5 +124,10 @@ int main(int, char**) { } } } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp index c07297a141ad10..846bcff63d7736 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -30,7 +30,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -67,15 +67,15 @@ void test() { assert(i == m.begin()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::iterator ii1{}, ii2{}; C::iterator ii4 = ii1; C::const_iterator cii{}; @@ -88,6 +88,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp index 29441dcc57d40e..3027cdd4076eea 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using KI = typename KeyContainer::iterator; @@ -144,11 +144,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp index a16383cdcf5383..d1e4cef3de19e8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include -int main(int, char**) { +void test() { { using M = std::flat_set, std::deque>; M m = {1, 2, 3, 4}; @@ -69,7 +69,7 @@ int main(int, char**) { } { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::reverse_iterator ii1{}, ii2{}; C::reverse_iterator ii4 = ii1; C::const_reverse_iterator cii{}; @@ -82,6 +82,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp index 221a13fa057577..efa13a51c30bb3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -38,7 +38,7 @@ static_assert(NoExceptClear, ThrowOnMoveContai #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -50,13 +50,17 @@ void test() { assert(m.size() == 0); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp index 95f7a3c5f5d34a..79800e894afbfc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -28,7 +28,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -121,21 +121,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp index de855d5e5c3009..b3bd8adf0c35d8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -27,7 +27,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = M::iterator; @@ -134,21 +134,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp index 386af04d26e9a2..42562b84b4e22d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -27,7 +27,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -106,16 +106,21 @@ void test() { assert(i8 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp index 7416977844e5df..d402a7ba0285ec 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -77,15 +77,21 @@ void test() { assert(i4 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp index 25d4f4af19608b..d81422d3871876 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template > -void test() { +void test_one() { using M = std::flat_set; auto make = [](std::initializer_list il) { @@ -70,22 +70,27 @@ void test() { assert(m.empty()); } -int main(int, char**) { - test>(); - test, std::greater<>>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one, std::greater<>>(); + test_one>(); + test_one>(); + test_one>>(); +} - { - auto erase_function = [](auto& m, auto key_arg) { - using Map = std::decay_t; - using Key = typename Map::key_type; - const Key key{key_arg}; - m.erase(key); - }; - test_erase_exception_guarantee(erase_function); - } +void test_exception() { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp index cbf7cac603806d..c383844eb4973e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -50,7 +50,7 @@ struct HeterogeneousKey { }; template -void test_simple() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -86,11 +86,11 @@ void test_transparent_comparator() { assert(m == expected); } -int main(int, char**) { - test_simple>(); - test_simple>(); - test_simple>(); - test_simple>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_transparent_comparator>(); test_transparent_comparator>(); @@ -129,14 +129,20 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } - { - auto erase_transparent = [](auto& m, auto key_arg) { - using Set = std::decay_t; - using Key = typename Set::key_type; - m.erase(Transparent{key_arg}); - }; - test_erase_exception_guarantee(erase_transparent); - } +} + +void test_exception() { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp index c3bbffabb90a08..dfa21a807f0254 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -33,7 +33,7 @@ static_assert(!CanExtract const&>); static_assert(!CanExtract const&&>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; M m = M({1, 2, 3}); @@ -45,11 +45,12 @@ void test() { LIBCPP_ASSERT(m.empty()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { // extracted object maintains invariant if the underlying container does not clear after move using M = std::flat_set, CopyOnlyVector>; @@ -59,7 +60,9 @@ int main(int, char**) { check_invariant(m); LIBCPP_ASSERT(m.empty()); } +} +void test_exception() { { #ifndef TEST_HAS_NO_EXCEPTIONS using KeyContainer = ThrowOnMoveContainer; @@ -79,5 +82,11 @@ int main(int, char**) { } #endif } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp index c0ddadc3006987..e0cb80f74462cd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -59,20 +59,25 @@ void test() { assert(*r.first == 3); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using value_type = typename std::decay_t::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(p); - }; - test_emplace_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp index 7381514a70eabb..bf94fd9f5b11fd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -23,12 +23,12 @@ #include "min_allocator.h" template -void test() { - using Key = typename KeyContainer::value_type; - using M = std::flat_set, KeyContainer>; - using V = typename M::value_type; +void test_one() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; - M m = {1,1,1,3,3,3}; + M m = {1, 1, 1, 3, 3, 3}; m.insert({ 4, 4, @@ -48,20 +48,26 @@ void test() { assert(*std::next(m.begin(), 3) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(il); - }; - test_insert_range_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index c343d53a62215a..d6791853e0debd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = typename M::iterator; @@ -55,13 +55,15 @@ void test() { assert(*r == 3); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; using value_type = typename FlatSet::value_type; @@ -69,6 +71,11 @@ int main(int, char**) { m.insert(m.begin(), p); }; test_emplace_exception_guarantee(insert_func); - } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp index d20a8ef8fdd92d..8063686c960ed3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; int ar1[] = { @@ -73,15 +73,22 @@ void test() { M expected2{0, 1, 2, 3, 4}; assert(m == expected2); } + +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp index 84b6c7fc1d34f6..d29de98e4d3ddb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -22,7 +22,7 @@ #include "test_macros.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -49,25 +49,30 @@ void test() { assert(*r == V(3)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(m.begin(), std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp index 536307252c6405..ed33827a7355c9 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -39,7 +39,7 @@ static_assert(!CanInsertRange*>>) static_assert(!CanInsertRange*>>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -75,31 +75,29 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { - // Items are forwarded correctly from the input range (P2767). + // Items are forwarded correctly from the input range. MoveOnly a[] = {3, 1, 4, 1, 5}; std::flat_set m; m.insert_range(a | std::views::as_rvalue); MoveOnly expected[] = {1, 3, 4, 5}; assert(std::ranges::equal(m, expected)); } - { - // The element type of the range doesn't need to be std::pair (P2767). - int pa[] = {3, 1, 4, 1, 5}; - std::deque> a(pa, pa + 5); - std::flat_set m; - m.insert_range(a); - int expected[] = {1, 3, 4, 5}; - assert(std::ranges::equal(m, expected)); - } - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; - test_insert_range_exception_guarantee(insert_func); - } +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp index 7d95f0521eb1f6..faf74142caff5c 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -25,7 +25,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; using R = std::pair; @@ -57,24 +57,30 @@ void test() { assert(*r.first == V(3)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp index fa5bf86830daec..38c36d1befaa7c 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -38,21 +38,26 @@ void test() { assert(*std::next(m.begin(), 4) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(std::sorted_unique, il); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp index ef7b8391cee33c..6258c4dbfdcbba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -60,18 +60,23 @@ void test() { assert(m == expected2); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - m.insert(std::sorted_unique, newValues.begin(), newValues.end()); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp index 72d7261a182547..d2ddf95aac2bb7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -57,7 +57,7 @@ struct CompareCounter { }; template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -121,11 +121,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // no ambiguity between insert(pos, P&&) and insert(first, last) @@ -139,6 +139,9 @@ int main(int, char**) { ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); } +} + +void test_exception() { { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; @@ -165,5 +168,11 @@ int main(int, char**) { }; test_emplace_exception_guarantee(insert_func_iter); } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp index 49cb6eb6163c90..fca33bd41449e0 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -31,7 +31,7 @@ static_assert(CanReplace>); static_assert(!CanReplace&>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -43,30 +43,36 @@ void test() { assert(std::ranges::equal(m, expected_keys)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { #ifndef TEST_HAS_NO_EXCEPTIONS - using KeyContainer = ThrowOnMoveContainer; - using M = std::flat_set; + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; - M m; - m.emplace(1); - m.emplace(2); - try { - KeyContainer new_keys{3, 4}; - m.replace(std::move(new_keys)); - assert(false); - } catch (int) { - check_invariant(m); - // In libc++, we clear the map - LIBCPP_ASSERT(m.size() == 0); - } -#endif + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); } +#endif +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp index bc7baa67e52a59..ed13ba1ef3fea7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -24,6 +24,8 @@ #include "test_macros.h" #include "../helpers.h" +#include "check_assertion.h" + // test noexcept template @@ -38,7 +40,7 @@ static_assert(NoExceptAdlSwap, ThrowOnMoveCont #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -84,11 +86,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp index b0b06a9499efc7..1eac55d768ce0b 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -37,7 +37,7 @@ static_assert(NoExceptMemberSwap, ThrowOnMoveC #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -82,11 +82,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp index 971b5e1c338dd1..ba2c428c9e30e2 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -21,7 +21,7 @@ #include "test_macros.h" -int main(int, char**) { +void test() { { using M = std::flat_set; using Comp = std::less; // the default @@ -67,6 +67,10 @@ int main(int, char**) { assert(vc(1, 2)); assert(!vc(2, 1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp index b14da66f611301..e23683f6f28945 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp index 507560608952b0..0cdff44d11274f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanContains); static_assert(!CanContains); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.contains(Transparent{"g"}) == false); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,5 +66,10 @@ int main(int, char**) { assert(b); assert(transparent_used); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp index 478f615358b606..017f0fed3e9816 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using S = typename KeyContainer::size_type; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp index b591258f74399c..0c5ce9d5799651 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanCount); static_assert(!CanCount); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.count(Transparent{"g"}) == 0); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,6 +66,10 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp index a088b7fee17d2c..b55cbe2ac42a00 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -67,11 +67,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp index ede5d91e19b9fd..97c4af19eaef37 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanEqualRange); static_assert(!CanEqualRange); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -77,11 +77,11 @@ void test() { test_not_found(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -92,6 +92,10 @@ int main(int, char**) { assert(p.first != p.second); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp index cf0dd2d1dd831c..9ee8f043e1d9cd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -25,7 +25,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m = {1, 2, 4, 5, 8}; @@ -43,11 +43,15 @@ void test() { assert(std::as_const(m).find(9) == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp index 730a57b0a6cb85..cc8ea12bcf4a6a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanFind); static_assert(!CanFind); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -68,11 +68,11 @@ void test() { test_find(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -83,6 +83,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp index 093c32e537ed35..1ceddb2f1c9d26 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -60,11 +60,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp index 18f9bc6dd32955..19991ca05fbc8a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanLowerBound); static_assert(!CanLowerBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,11 @@ void test() { test_lower_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -89,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp index ab34de85103175..f25896e1229397 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -61,11 +61,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp index 69ce2ae926a305..c9b519d2032193 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanUpperBound); static_assert(!CanUpperBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,12 @@ void test() { test_upper_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { bool transparent_used = false; TransparentComparator c(transparent_used); @@ -88,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h index 9fff262d84234e..2ee8b021337a06 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SUPPORT_flat_set_HELPERS_H -#define SUPPORT_flat_set_HELPERS_H +#ifndef SUPPORT_FLAT_SET_HELPERS_H +#define SUPPORT_FLAT_SET_HELPERS_H #include #include @@ -149,6 +149,19 @@ struct EmplaceUnsafeContainer : std::vector { throw 42; } + + template + auto insert_range(Args&&... args) + -> decltype(std::declval>().insert_range(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } }; template @@ -291,4 +304,4 @@ class Moveable { bool moved() const { return int_ == -1; } }; -#endif // SUPPORT_flat_set_HELPERS_H +#endif // SUPPORT_FLAT_SET_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp index c4a9810016536b..faf746861df309 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -27,7 +27,10 @@ struct A { // Implement the operator< required in order to instantiate flat_set bool operator<(A const& L, A const& R) { return L.data < R.data; } +void test() { A a; } + int main(int, char**) { - A a; + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp index f6d08bb736d300..3e7aecee77fdd8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -31,7 +31,7 @@ #include "test_container_comparisons.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -69,11 +69,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { using C = std::flat_set; @@ -101,5 +101,10 @@ int main(int, char**) { assert(s1 != s2); assert((s1 <=> s2) == std::partial_ordering::unordered); } +} + +int main(int, char**) { + test(); + return 0; } >From 6fa4b5763cccee5d1631d9239c12f33d5c656956 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 14:08:01 +0000 Subject: [PATCH 3/5] review --- .../flat.set/assert.sorted_unique.pass.cpp | 226 ++++++++++++++++++ .../assign_initializer_list.pass.cpp | 6 +- .../flat.set.cons/move_assign.pass.cpp | 67 ++++-- 3 files changed, 280 insertions(+), 19 deletions(-) create mode 100644 libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp diff --git a/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp new file mode 100644 index 00000000000000..62903af7f4e477 --- /dev/null +++ b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp @@ -0,0 +1,226 @@ +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: libcpp-hardening-mode=none +// REQUIRES: libcpp-hardening-mode=debug +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// + +// flat_set(container_type , const key_compare& __comp = key_compare()) +// flat_set(const container_type& , const _Allocator& ) +// flat_set(const container_type& , const key_compare&, const _Allocator& ) +// void replace(container_type&& ) +// + +#include +#include +#include +#include +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + using M = std::flat_set; + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{1, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{2, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7e948d7c5fe976..ad49b621490366 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -30,14 +30,16 @@ void test_one() { { M m = {8, 10}; assert(m.size() == 2); - m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + std::same_as decltype(auto) r = m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + assert(&r == &m); int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); } { M m = {10, 8}; assert(m.size() == 2); - m = {3}; + std::same_as decltype(auto) r = m = {3}; + assert(&r == &m); int expected[] = {3}; assert(std::ranges::equal(m, expected)); } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index e55a0516ed1bed..0e0ab0aa135f9f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -55,6 +55,19 @@ struct MoveClears { auto operator<=>(const MoveClears&) const = default; }; +#if !defined(TEST_HAS_NO_EXCEPTIONS) +struct MoveAssignThrows : std::vector { + using std::vector::vector; + MoveAssignThrows& operator=(MoveAssignThrows&& other) { + push_back(0); + push_back(0); + other.push_back(0); + other.push_back(0); + throw 42; + } +}; +#endif // TEST_HAS_NO_EXCEPTIONS + void test_move_assign_clears() { // Preserves the class invariant for the moved-from flat_set. { @@ -101,6 +114,23 @@ void test_move_assign_clears() { check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +#if !defined(TEST_HAS_NO_EXCEPTIONS) + { + using M = std::flat_set, MoveAssignThrows>; + M m1 = {1, 2, 3}; + M m2 = {1, 2}; + try { + m2 = std::move(m1); + assert(false); + } catch (int e) { + assert(e == 42); + } + check_invariant(m1); + check_invariant(m2); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m2.empty()); + } +#endif // TEST_HAS_NO_EXCEPTIONS } struct MoveSensitiveComp { @@ -161,12 +191,13 @@ void test_move_assign_no_except() { void test() { { - using C = test_less; - using A1 = test_allocator; - using M = std::flat_set>; - M mo = M({1, 2, 3}, C(5), A1(7)); - M m = M({}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{1, 2, 3})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -174,12 +205,13 @@ void test() { assert(mo.empty()); } { - using C = test_less; - using A1 = other_allocator; - using M = std::flat_set>; - M mo = M({4, 5}, C(5), A1(7)); - M m = M({1, 2, 3, 4}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{4, 5})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -187,11 +219,12 @@ void test() { assert(mo.empty()); } { - using A = min_allocator; - using M = std::flat_set, std::vector>; - M mo = M({5, 4, 3}, A()); - M m = M({4, 3, 2, 1}, A()); - m = std::move(mo); + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{5, 4, 3})); auto ks = std::move(m).extract(); assert(ks.get_allocator() == A()); >From c65a37ea8012b92dc5575be91a1a18851a8caeaa Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 16:23:56 +0000 Subject: [PATCH 4/5] clang-format --- .../flat.set/flat.set.capacity/max_size.pass.cpp | 1 - .../flat.set.modifiers/insert_iter_cv.pass.cpp | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index 0489d886257911..dde1f7092e5b18 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -25,7 +25,6 @@ #include "test_macros.h" void test() { - { using A1 = limited_allocator; using C = std::flat_set, std::vector>; diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index d6791853e0debd..76b4d5f0eb7cc6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -56,7 +56,6 @@ void test_one() { } void test() { - test_one>(); test_one>(); test_one>(); @@ -64,13 +63,13 @@ void test() { } void test_exception() { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(m.begin(), p); - }; - test_emplace_exception_guarantee(insert_func); + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); } int main(int, char**) { >From 61147247cfcf3fd4623587bddaa07a2c4783d2b6 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 16:59:41 +0000 Subject: [PATCH 5/5] CI --- libcxx/docs/ReleaseNotes/21.rst | 1 + libcxx/docs/Status/Cxx23Papers.csv | 2 +- libcxx/modules/std.compat.cppm.in | 3 - libcxx/modules/std.cppm.in | 4 +- libcxx/modules/std/flat_set.inc | 4 +- .../test/libcxx/transitive_includes/cxx03.csv | 8 ++ .../test/libcxx/transitive_includes/cxx11.csv | 8 ++ .../test/libcxx/transitive_includes/cxx14.csv | 8 ++ .../test/libcxx/transitive_includes/cxx17.csv | 8 ++ .../test/libcxx/transitive_includes/cxx20.csv | 8 ++ .../test/libcxx/transitive_includes/cxx23.csv | 15 +++- .../test/libcxx/transitive_includes/cxx26.csv | 14 ++++ .../flat_set.version.compile.pass.cpp | 80 +++++++++++++++++++ libcxx/utils/libcxx/header_information.py | 2 +- 14 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad3942..0c1029f50a6fe7 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -39,6 +39,7 @@ Implemented Papers ------------------ - N4258: Cleaning-up noexcept in the Library (`Github `__) +- P1222R4: A Standard ``flat_set`` is partially implemented and ``flat_set`` is provided (`Github `__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 264c5417a5c28b..bcd9c5c43a9c69 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -54,7 +54,7 @@ "`P0009R18 `__","mdspan: A Non-Owning Multidimensional Array Reference","2022-07 (Virtual)","|Complete|","18","" "`P0429R9 `__","A Standard ``flat_map``","2022-07 (Virtual)","|Complete|","20","" "`P1169R4 `__","``static operator()``","2022-07 (Virtual)","|Complete|","16","" -"`P1222R4 `__","A Standard ``flat_set``","2022-07 (Virtual)","","","" +"`P1222R4 `__","A Standard ``flat_set``","2022-07 (Virtual)","|In progress|","","" "`P1223R5 `__","``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()``","2022-07 (Virtual)","|Complete|","19","" "`P1467R9 `__","Extended ``floating-point`` types and standard names","2022-07 (Virtual)","","","" "`P1642R11 `__","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","2022-07 (Virtual)","","","" diff --git a/libcxx/modules/std.compat.cppm.in b/libcxx/modules/std.compat.cppm.in index 5cea1b75bfc170..95931447ccdc64 100644 --- a/libcxx/modules/std.compat.cppm.in +++ b/libcxx/modules/std.compat.cppm.in @@ -53,9 +53,6 @@ module; # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in index b9d00df70658d8..5c523691bff4e2 100644 --- a/libcxx/modules/std.cppm.in +++ b/libcxx/modules/std.cppm.in @@ -65,6 +65,7 @@ module; #include #include #include +#include #include #include #if _LIBCPP_HAS_LOCALIZATION @@ -162,9 +163,6 @@ module; # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std/flat_set.inc b/libcxx/modules/std/flat_set.inc index a86cc1eae02a62..3f2c6e09a0ebe4 100644 --- a/libcxx/modules/std/flat_set.inc +++ b/libcxx/modules/std/flat_set.inc @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// export namespace std { -#if 0 +#if _LIBCPP_STD_VER >= 23 // [flat.set], class template flat_­set using std::flat_set; @@ -19,7 +19,9 @@ export namespace std { // [flat.set.erasure], erasure for flat_­set using std::erase_if; +#endif // _LIBCPP_STD_VER >= 23 +#if 0 // [flat.multiset], class template flat_­multiset using std::flat_multiset; diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv index ec5db90597d927..c0031543e47bce 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -683,6 +683,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv index ec5db90597d927..c0031543e47bce 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -683,6 +683,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv index 95024df0590b84..c2eb5b44e8d7a7 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -701,6 +701,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv index a3518f7f62ecb9..332cb62f35b5f4 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -709,6 +709,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv index 6de95139279471..55c79acff5a8f9 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -705,6 +705,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv index 17972b84537436..7da07a8b3749b2 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -345,6 +345,20 @@ flat_map optional flat_map stdexcept flat_map tuple flat_map version +flat_set cctype +flat_set climits +flat_set compare +flat_set cstdint +flat_set cstring +flat_set cwchar +flat_set cwctype +flat_set initializer_list +flat_set limits +flat_set optional +flat_set stdexcept +flat_set tuple +flat_set type_traits +flat_set version format array format cctype format cerrno @@ -556,7 +570,6 @@ istream ios istream iosfwd istream limits istream locale - istream ratio istream stdexcept istream streambuf diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv index 00ab78e61a4576..4c2782a4ce5cf9 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -345,6 +345,20 @@ flat_map optional flat_map stdexcept flat_map tuple flat_map version +flat_set cctype +flat_set climits +flat_set compare +flat_set cstdint +flat_set cstring +flat_set cwchar +flat_set cwctype +flat_set initializer_list +flat_set limits +flat_set optional +flat_set stdexcept +flat_set tuple +flat_set type_traits +flat_set version format array format cctype format cerrno diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp new file mode 100644 index 00000000000000..f9d0b0a6b4e4f6 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. +// +// clang-format off + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_flat_set 202207L [C++23] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should be defined in c++23" +# endif +# if __cpp_lib_flat_set != 202207L +# error "__cpp_lib_flat_set should have the value 202207L in c++23" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#elif TEST_STD_VER > 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should be defined in c++26" +# endif +# if __cpp_lib_flat_set != 202207L +# error "__cpp_lib_flat_set should have the value 202207L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#endif // TEST_STD_VER > 23 + diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py index 9a723b61524cd5..9811b42d510ca3 100644 --- a/libcxx/utils/libcxx/header_information.py +++ b/libcxx/utils/libcxx/header_information.py @@ -164,7 +164,6 @@ def __hash__(self) -> int: # modules will fail to build if a header is added but this list is not updated. headers_not_available = list(map(Header, [ "debugging", - "flat_set", "generator", "hazard_pointer", "inplace_vector", @@ -261,6 +260,7 @@ def __hash__(self) -> int: "deque": ["compare", "initializer_list"], "filesystem": ["compare"], "flat_map": ["compare", "initializer_list"], + "flat_set": ["compare", "initializer_list"], "forward_list": ["compare", "initializer_list"], "ios": ["iosfwd"], "iostream": ["ios", "istream", "ostream", "streambuf"], From libcxx-commits at lists.llvm.org Sun Feb 2 09:07:34 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 09:07:34 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix basic_string not allowing max_size() elements to be stored (PR #125423) Message-ID: https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/125423 Without this patch `basic_string` cannot be properly resized to be `max_size()` elements in size, even if an allocation is successful. `__grow_by` allocates one less element than required, resulting in an out-of-bounds access. At the same time, `max_size()` has an off-by-one error, since there has to be space to store the null terminator, which is currently ignored. >From d49f406148c3ad347501331f89a4e059c32d2f73 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Sun, 2 Feb 2025 18:01:27 +0100 Subject: [PATCH] [libc++] Fix basic_string not allowing max_size() elements to be stored --- libcxx/include/string | 6 +-- .../string.capacity/max_size.pass.cpp | 20 ++++----- .../string.capacity/max_size.pass.cpp | 10 ++++- .../string.capacity/resize_size.pass.cpp | 44 ++++++++++++------- libcxx/test/support/min_allocator.h | 28 ++++++++++++ 5 files changed, 77 insertions(+), 31 deletions(-) diff --git a/libcxx/include/string b/libcxx/include/string index fdd8085106dcc60..892ae97518f719e 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -1305,10 +1305,10 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type max_size() const _NOEXCEPT { size_type __m = __alloc_traits::max_size(__alloc_); if (__m <= std::numeric_limits::max() / 2) { - return __m - __alignment; + return __m - __alignment - 1; } else { bool __uses_lsb = __endian_factor == 2; - return __uses_lsb ? __m - __alignment : (__m / 2) - __alignment; + return __uses_lsb ? __m - __alignment - 1 : (__m / 2) - __alignment - 1; } } @@ -2558,7 +2558,7 @@ _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Trait __throw_length_error(); pointer __old_p = __get_pointer(); size_type __cap = - __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; + __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms; auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1); pointer __p = __allocation.ptr; __begin_lifetime(__p, __allocation.count); diff --git a/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp index 726570beb6d1ae6..e097c70ec79a7c1 100644 --- a/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp +++ b/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp @@ -23,44 +23,44 @@ static const std::size_t alignment = 8; template TEST_CONSTEXPR_CXX20 void full_size() { std::string str; - assert(str.max_size() == std::numeric_limits::max() - alignment); + assert(str.max_size() == std::numeric_limits::max() - alignment - 1); #ifndef TEST_HAS_NO_CHAR8_T std::u8string u8str; - assert(u8str.max_size() == std::numeric_limits::max() - alignment); + assert(u8str.max_size() == std::numeric_limits::max() - alignment - 1); #endif #ifndef TEST_HAS_NO_WIDE_CHARACTERS std::wstring wstr; - assert(wstr.max_size() == std::numeric_limits::max() / sizeof(wchar_t) - alignment); + assert(wstr.max_size() == std::numeric_limits::max() / sizeof(wchar_t) - alignment - 1); #endif std::u16string u16str; std::u32string u32str; - assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment); - assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment); + assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); + assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment - 1); } template TEST_CONSTEXPR_CXX20 void half_size() { std::string str; - assert(str.max_size() == std::numeric_limits::max() / 2 - alignment); + assert(str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); #ifndef TEST_HAS_NO_CHAR8_T std::u8string u8str; - assert(u8str.max_size() == std::numeric_limits::max() / 2 - alignment); + assert(u8str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); #endif #ifndef TEST_HAS_NO_WIDE_CHARACTERS std::wstring wstr; assert(wstr.max_size() == - std::numeric_limits::max() / std::max(2ul, sizeof(wchar_t)) - alignment); + std::numeric_limits::max() / std::max(2ul, sizeof(wchar_t)) - alignment - 1); #endif std::u16string u16str; std::u32string u32str; - assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment); - assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment); + assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); + assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment - 1); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp index b9ffffc0993af89..ff38a59cb00e58e 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp @@ -53,7 +53,7 @@ TEST_CONSTEXPR_CXX20 void test_resize_max_size(const S& s) { } catch (const std::bad_alloc&) { return; } - assert(s.size() == sz); + assert(s2.size() == sz); } template @@ -91,8 +91,16 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator > >(); + test_string, tiny_size_allocator<64, char> > >(); #endif + { // Test resizing where we can assume that the allocation succeeds + std::basic_string, tiny_size_allocator<32, char> > str; + auto max_size = str.max_size(); + str.resize(max_size); + assert(str.size() == max_size); + } + return true; } diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp index 7cf4b7ca3b6efd6..99b654cf6b6a513 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp @@ -20,22 +20,10 @@ template TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, S expected) { - if (n <= s.max_size()) { - s.resize(n); - LIBCPP_ASSERT(s.__invariants()); - assert(s == expected); - LIBCPP_ASSERT(is_string_asan_correct(s)); - } -#ifndef TEST_HAS_NO_EXCEPTIONS - else if (!TEST_IS_CONSTANT_EVALUATED) { - try { - s.resize(n); - assert(false); - } catch (std::length_error&) { - assert(n > s.max_size()); - } - } -#endif + s.resize(n); + LIBCPP_ASSERT(s.__invariants()); + assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template @@ -56,7 +44,26 @@ TEST_CONSTEXPR_CXX20 void test_string() { test(S("12345678901234567890123456789012345678901234567890"), 60, S("12345678901234567890123456789012345678901234567890\0\0\0\0\0\0\0\0\0\0", 60)); - test(S(), S::npos, S("not going to happen")); +} + +template +TEST_CONSTEXPR_CXX20 void test_max_size() { +#ifndef TEST_HAS_NO_EXCEPTIONS + if (!TEST_IS_CONSTANT_EVALUATED) { + std::basic_string str; + try { + str.resize(std::string::npos); + assert(false); + } catch (const std::length_error&) { + } + } +#endif + + { + std::basic_string, tiny_size_allocator<32, CharT>> str; + str.resize(str.max_size()); + assert(str.size() == str.max_size()); + } } TEST_CONSTEXPR_CXX20 bool test() { @@ -66,6 +73,9 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string, safe_allocator>>(); #endif + test_max_size(); + test_max_size(); + return true; } diff --git a/libcxx/test/support/min_allocator.h b/libcxx/test/support/min_allocator.h index 18f51f8072640d1..f050267dc4ef759 100644 --- a/libcxx/test/support/min_allocator.h +++ b/libcxx/test/support/min_allocator.h @@ -480,4 +480,32 @@ class safe_allocator { TEST_CONSTEXPR_CXX20 friend bool operator!=(safe_allocator x, safe_allocator y) { return !(x == y); } }; +template +struct tiny_size_allocator { + using value_type = T; + using size_type = unsigned; + + template + struct rebind { + using other = tiny_size_allocator; + }; + + tiny_size_allocator() = default; + + template + TEST_CONSTEXPR_CXX20 tiny_size_allocator(tiny_size_allocator) {} + + TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { + assert(n <= MaxSize); + return std::allocator{}.allocate(n); + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* ptr, std::size_t n) { std::allocator{}.deallocate(ptr, n); } + + TEST_CONSTEXPR_CXX20 size_type max_size() const { return MaxSize; } + + friend bool operator==(tiny_size_allocator, tiny_size_allocator) { return true; } + friend bool operator!=(tiny_size_allocator, tiny_size_allocator) { return false; } +}; + #endif // MIN_ALLOCATOR_H From libcxx-commits at lists.llvm.org Sun Feb 2 09:08:05 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Sun, 02 Feb 2025 09:08:05 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix basic_string not allowing max_size() elements to be stored (PR #125423) In-Reply-To: Message-ID: <679fa675.050a0220.1ad2d9.46c2@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-libcxx Author: Nikolas Klauser (philnik777)
Changes Without this patch `basic_string` cannot be properly resized to be `max_size()` elements in size, even if an allocation is successful. `__grow_by` allocates one less element than required, resulting in an out-of-bounds access. At the same time, `max_size()` has an off-by-one error, since there has to be space to store the null terminator, which is currently ignored. --- Full diff: https://github.com/llvm/llvm-project/pull/125423.diff 5 Files Affected: - (modified) libcxx/include/string (+3-3) - (modified) libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp (+10-10) - (modified) libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp (+9-1) - (modified) libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp (+27-17) - (modified) libcxx/test/support/min_allocator.h (+28) ``````````diff diff --git a/libcxx/include/string b/libcxx/include/string index fdd8085106dcc6..892ae97518f719 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -1305,10 +1305,10 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type max_size() const _NOEXCEPT { size_type __m = __alloc_traits::max_size(__alloc_); if (__m <= std::numeric_limits::max() / 2) { - return __m - __alignment; + return __m - __alignment - 1; } else { bool __uses_lsb = __endian_factor == 2; - return __uses_lsb ? __m - __alignment : (__m / 2) - __alignment; + return __uses_lsb ? __m - __alignment - 1 : (__m / 2) - __alignment - 1; } } @@ -2558,7 +2558,7 @@ _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Trait __throw_length_error(); pointer __old_p = __get_pointer(); size_type __cap = - __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; + __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms; auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1); pointer __p = __allocation.ptr; __begin_lifetime(__p, __allocation.count); diff --git a/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp index 726570beb6d1ae..e097c70ec79a7c 100644 --- a/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp +++ b/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp @@ -23,44 +23,44 @@ static const std::size_t alignment = 8; template TEST_CONSTEXPR_CXX20 void full_size() { std::string str; - assert(str.max_size() == std::numeric_limits::max() - alignment); + assert(str.max_size() == std::numeric_limits::max() - alignment - 1); #ifndef TEST_HAS_NO_CHAR8_T std::u8string u8str; - assert(u8str.max_size() == std::numeric_limits::max() - alignment); + assert(u8str.max_size() == std::numeric_limits::max() - alignment - 1); #endif #ifndef TEST_HAS_NO_WIDE_CHARACTERS std::wstring wstr; - assert(wstr.max_size() == std::numeric_limits::max() / sizeof(wchar_t) - alignment); + assert(wstr.max_size() == std::numeric_limits::max() / sizeof(wchar_t) - alignment - 1); #endif std::u16string u16str; std::u32string u32str; - assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment); - assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment); + assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); + assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment - 1); } template TEST_CONSTEXPR_CXX20 void half_size() { std::string str; - assert(str.max_size() == std::numeric_limits::max() / 2 - alignment); + assert(str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); #ifndef TEST_HAS_NO_CHAR8_T std::u8string u8str; - assert(u8str.max_size() == std::numeric_limits::max() / 2 - alignment); + assert(u8str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); #endif #ifndef TEST_HAS_NO_WIDE_CHARACTERS std::wstring wstr; assert(wstr.max_size() == - std::numeric_limits::max() / std::max(2ul, sizeof(wchar_t)) - alignment); + std::numeric_limits::max() / std::max(2ul, sizeof(wchar_t)) - alignment - 1); #endif std::u16string u16str; std::u32string u32str; - assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment); - assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment); + assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); + assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment - 1); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp index b9ffffc0993af8..ff38a59cb00e58 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp @@ -53,7 +53,7 @@ TEST_CONSTEXPR_CXX20 void test_resize_max_size(const S& s) { } catch (const std::bad_alloc&) { return; } - assert(s.size() == sz); + assert(s2.size() == sz); } template @@ -91,8 +91,16 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator > >(); + test_string, tiny_size_allocator<64, char> > >(); #endif + { // Test resizing where we can assume that the allocation succeeds + std::basic_string, tiny_size_allocator<32, char> > str; + auto max_size = str.max_size(); + str.resize(max_size); + assert(str.size() == max_size); + } + return true; } diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp index 7cf4b7ca3b6efd..99b654cf6b6a51 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp @@ -20,22 +20,10 @@ template TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, S expected) { - if (n <= s.max_size()) { - s.resize(n); - LIBCPP_ASSERT(s.__invariants()); - assert(s == expected); - LIBCPP_ASSERT(is_string_asan_correct(s)); - } -#ifndef TEST_HAS_NO_EXCEPTIONS - else if (!TEST_IS_CONSTANT_EVALUATED) { - try { - s.resize(n); - assert(false); - } catch (std::length_error&) { - assert(n > s.max_size()); - } - } -#endif + s.resize(n); + LIBCPP_ASSERT(s.__invariants()); + assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template @@ -56,7 +44,26 @@ TEST_CONSTEXPR_CXX20 void test_string() { test(S("12345678901234567890123456789012345678901234567890"), 60, S("12345678901234567890123456789012345678901234567890\0\0\0\0\0\0\0\0\0\0", 60)); - test(S(), S::npos, S("not going to happen")); +} + +template +TEST_CONSTEXPR_CXX20 void test_max_size() { +#ifndef TEST_HAS_NO_EXCEPTIONS + if (!TEST_IS_CONSTANT_EVALUATED) { + std::basic_string str; + try { + str.resize(std::string::npos); + assert(false); + } catch (const std::length_error&) { + } + } +#endif + + { + std::basic_string, tiny_size_allocator<32, CharT>> str; + str.resize(str.max_size()); + assert(str.size() == str.max_size()); + } } TEST_CONSTEXPR_CXX20 bool test() { @@ -66,6 +73,9 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string, safe_allocator>>(); #endif + test_max_size(); + test_max_size(); + return true; } diff --git a/libcxx/test/support/min_allocator.h b/libcxx/test/support/min_allocator.h index 18f51f8072640d..f050267dc4ef75 100644 --- a/libcxx/test/support/min_allocator.h +++ b/libcxx/test/support/min_allocator.h @@ -480,4 +480,32 @@ class safe_allocator { TEST_CONSTEXPR_CXX20 friend bool operator!=(safe_allocator x, safe_allocator y) { return !(x == y); } }; +template +struct tiny_size_allocator { + using value_type = T; + using size_type = unsigned; + + template + struct rebind { + using other = tiny_size_allocator; + }; + + tiny_size_allocator() = default; + + template + TEST_CONSTEXPR_CXX20 tiny_size_allocator(tiny_size_allocator) {} + + TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { + assert(n <= MaxSize); + return std::allocator{}.allocate(n); + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* ptr, std::size_t n) { std::allocator{}.deallocate(ptr, n); } + + TEST_CONSTEXPR_CXX20 size_type max_size() const { return MaxSize; } + + friend bool operator==(tiny_size_allocator, tiny_size_allocator) { return true; } + friend bool operator!=(tiny_size_allocator, tiny_size_allocator) { return false; } +}; + #endif // MIN_ALLOCATOR_H ``````````
https://github.com/llvm/llvm-project/pull/125423 From libcxx-commits at lists.llvm.org Sun Feb 2 09:13:29 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Sun, 02 Feb 2025 09:13:29 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix basic_string not allowing max_size() elements to be stored (PR #125423) In-Reply-To: Message-ID: <679fa7b9.170a0220.d6d8.5410@mx.google.com> github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning:
You can test this locally with the following command: ``````````bash git-clang-format --diff 6dd07b17c7ff8e61073a7732e09fa828a64f7bec d49f406148c3ad347501331f89a4e059c32d2f73 --extensions ,cpp,h -- libcxx/include/string libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp libcxx/test/support/min_allocator.h ``````````
View the diff from clang-format here. ``````````diff diff --git a/libcxx/test/support/min_allocator.h b/libcxx/test/support/min_allocator.h index f050267dc4..1463be722e 100644 --- a/libcxx/test/support/min_allocator.h +++ b/libcxx/test/support/min_allocator.h @@ -483,7 +483,7 @@ public: template struct tiny_size_allocator { using value_type = T; - using size_type = unsigned; + using size_type = unsigned; template struct rebind { ``````````
https://github.com/llvm/llvm-project/pull/125423 From libcxx-commits at lists.llvm.org Sun Feb 2 09:52:33 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 09:52:33 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Simplify vector::__construct_at_end (Reopend) (PR #119632) In-Reply-To: Message-ID: <679fb0e1.170a0220.60d90.e541@mx.google.com> ================ @@ -552,36 +552,29 @@ vector::__recommend(size_type __new_size) const { } // Default constructs __n objects starting at __end_ -// Precondition: __n > 0 // Precondition: size() + __n <= capacity() // Postcondition: size() == size() + __n template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__construct_at_end(size_type __n, bool __x) { - size_type __old_size = this->__size_; + _LIBCPP_ASSERT_INTERNAL( + capacity() >= size() + __n, "vector::__construct_at_end called with insufficient capacity"); + std::fill_n(end(), __n, __x); this->__size_ += __n; - if (__old_size == 0 || ((__old_size - 1) / __bits_per_word) != ((this->__size_ - 1) / __bits_per_word)) { - if (this->__size_ <= __bits_per_word) - this->__begin_[0] = __storage_type(0); - else - this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0); - } - std::fill_n(__make_iter(__old_size), __n, __x); + if (end().__ctz_ != 0) // Ensure uninitialized leading bits in the last word are set to zero + std::fill_n(end(), __bits_per_word - end().__ctz_, 0); ---------------- philnik777 wrote: Why is this required? https://github.com/llvm/llvm-project/pull/119632 From libcxx-commits at lists.llvm.org Sun Feb 2 09:52:33 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 09:52:33 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Simplify vector::__construct_at_end (Reopend) (PR #119632) In-Reply-To: Message-ID: <679fb0e1.170a0220.35c67a.2434@mx.google.com> ================ @@ -552,36 +552,29 @@ vector::__recommend(size_type __new_size) const { } // Default constructs __n objects starting at __end_ -// Precondition: __n > 0 // Precondition: size() + __n <= capacity() // Postcondition: size() == size() + __n template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__construct_at_end(size_type __n, bool __x) { - size_type __old_size = this->__size_; + _LIBCPP_ASSERT_INTERNAL( + capacity() >= size() + __n, "vector::__construct_at_end called with insufficient capacity"); + std::fill_n(end(), __n, __x); this->__size_ += __n; - if (__old_size == 0 || ((__old_size - 1) / __bits_per_word) != ((this->__size_ - 1) / __bits_per_word)) { - if (this->__size_ <= __bits_per_word) - this->__begin_[0] = __storage_type(0); - else - this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0); - } - std::fill_n(__make_iter(__old_size), __n, __x); + if (end().__ctz_ != 0) // Ensure uninitialized leading bits in the last word are set to zero + std::fill_n(end(), __bits_per_word - end().__ctz_, 0); } template template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n) { ---------------- philnik777 wrote: Is there a test for this function where `_InputIterator` isn't a `vector` iterator? e.g. `bool*`. I don't see how the elements are initialized which makes me think that we may read from uninitialized memory when the `__bit_iterator` optimization in `std::copy` doesn't kick in. I don't think this is a problem in reality, since we're setting the bits one-by-one, but could cause some sanitizer to complain. https://github.com/llvm/llvm-project/pull/119632 From libcxx-commits at lists.llvm.org Sun Feb 2 09:58:55 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Sun, 02 Feb 2025 09:58:55 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Simplify vector::__construct_at_end (Reopend) (PR #119632) In-Reply-To: Message-ID: <679fb25f.050a0220.2ce41d.4ccd@mx.google.com> ================ @@ -552,36 +552,29 @@ vector::__recommend(size_type __new_size) const { } // Default constructs __n objects starting at __end_ -// Precondition: __n > 0 // Precondition: size() + __n <= capacity() // Postcondition: size() == size() + __n template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__construct_at_end(size_type __n, bool __x) { - size_type __old_size = this->__size_; + _LIBCPP_ASSERT_INTERNAL( + capacity() >= size() + __n, "vector::__construct_at_end called with insufficient capacity"); + std::fill_n(end(), __n, __x); this->__size_ += __n; - if (__old_size == 0 || ((__old_size - 1) / __bits_per_word) != ((this->__size_ - 1) / __bits_per_word)) { - if (this->__size_ <= __bits_per_word) - this->__begin_[0] = __storage_type(0); - else - this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0); - } - std::fill_n(__make_iter(__old_size), __n, __x); + if (end().__ctz_ != 0) // Ensure uninitialized leading bits in the last word are set to zero + std::fill_n(end(), __bits_per_word - end().__ctz_, 0); ---------------- winner245 wrote: This ensures that the unused leading bits in the last word are initialized, which serves the same purpose as the pre-initialization logic in the previous implementation: https://github.com/llvm/llvm-project/blob/743c84bb9b79ed70d9bed926c2a173db3b30f587/libcxx/include/__vector/vector_bool.h#L554-L561 Without this, we would have a Msan CI failure. https://github.com/llvm/llvm-project/pull/119632 From libcxx-commits at lists.llvm.org Sun Feb 2 10:06:33 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Sun, 02 Feb 2025 10:06:33 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] implement std::flat_set (PR #125241) In-Reply-To: Message-ID: <679fb429.170a0220.38024a.768d@mx.google.com> https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/125241 >From f315d757119fde3cf298c18914a33e9cf76f27d1 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Fri, 31 Jan 2025 15:53:09 +0000 Subject: [PATCH 1/6] [libc++] implement std::flat_set --- libcxx/include/CMakeLists.txt | 2 + libcxx/include/__flat_set/flat_set.h | 853 ++++++++++++++++++ libcxx/include/flat_set | 59 ++ libcxx/include/module.modulemap | 11 + .../flat.set/flat.set.capacity/empty.pass.cpp | 48 + .../flat.set.capacity/empty.verify.cpp | 20 + .../flat.set.capacity/max_size.pass.cpp | 63 ++ .../flat.set/flat.set.capacity/size.pass.cpp | 66 ++ .../flat.set/flat.set.cons/alloc.pass.cpp | 60 ++ .../assign_initializer_list.pass.cpp | 56 ++ .../flat.set/flat.set.cons/compare.pass.cpp | 83 ++ .../flat.set.cons/containers.pass.cpp | 158 ++++ .../flat.set/flat.set.cons/copy.pass.cpp | 64 ++ .../flat.set.cons/copy_alloc.pass.cpp | 63 ++ .../copy_assign.addressof.compile.pass.cpp | 30 + .../flat.set.cons/copy_assign.pass.cpp | 85 ++ .../flat.set.cons/deduct.compile.pass.cpp | 49 + .../flat.set/flat.set.cons/deduct.pass.cpp | 341 +++++++ .../flat.set.cons/deduct_pmr.pass.cpp | 94 ++ .../flat.set/flat.set.cons/default.pass.cpp | 65 ++ .../flat.set.cons/default_noexcept.pass.cpp | 58 ++ .../flat.set.cons/dtor_noexcept.pass.cpp | 57 ++ .../flat.set.cons/initializer_list.pass.cpp | 151 ++++ .../flat.set/flat.set.cons/iter_iter.pass.cpp | 136 +++ .../flat.set/flat.set.cons/move.pass.cpp | 83 ++ .../flat.set.cons/move_alloc.pass.cpp | 75 ++ .../flat.set.cons/move_assign.pass.cpp | 69 ++ .../flat.set.cons/move_assign_clears.pass.cpp | 101 +++ .../move_assign_noexcept.pass.cpp | 85 ++ .../flat.set.cons/move_exceptions.pass.cpp | 58 ++ .../flat.set.cons/move_noexcept.pass.cpp | 94 ++ .../flat.set/flat.set.cons/pmr.pass.cpp | 322 +++++++ .../flat.set/flat.set.cons/range.pass.cpp | 173 ++++ .../flat.set.cons/sorted_container.pass.cpp | 143 +++ .../sorted_initializer_list.pass.cpp | 150 +++ .../flat.set.cons/sorted_iter_iter.pass.cpp | 156 ++++ .../flat.set.erasure/erase_if.pass.cpp | 89 ++ .../erase_if_exceptions.pass.cpp | 128 +++ .../flat.set.iterators/iterator.pass.cpp | 93 ++ .../iterator_comparison.pass.cpp | 154 ++++ ...rator_concept_conformance.compile.pass.cpp | 77 ++ ...range_concept_conformance.compile.pass.cpp | 52 ++ .../reverse_iterator.pass.cpp | 87 ++ .../flat.set.modifiers/clear.pass.cpp | 62 ++ .../flat.set.modifiers/emplace.pass.cpp | 141 +++ .../flat.set.modifiers/emplace_hint.pass.cpp | 154 ++++ .../flat.set.modifiers/erase_iter.pass.cpp | 121 +++ .../erase_iter_iter.pass.cpp | 91 ++ .../flat.set.modifiers/erase_key.pass.cpp | 91 ++ .../erase_key_transparent.pass.cpp | 142 +++ .../flat.set.modifiers/extract.pass.cpp | 83 ++ .../flat.set.modifiers/insert_cv.pass.cpp | 78 ++ .../insert_initializer_list.pass.cpp | 67 ++ .../insert_iter_cv.pass.cpp | 74 ++ .../insert_iter_iter.pass.cpp | 87 ++ .../insert_iter_rv.pass.cpp | 73 ++ .../flat.set.modifiers/insert_range.pass.cpp | 105 +++ .../flat.set.modifiers/insert_rv.pass.cpp | 80 ++ .../insert_sorted_initializer_list.pass.cpp | 58 ++ .../insert_sorted_iter_iter.pass.cpp | 77 ++ .../insert_transparent.pass.cpp | 169 ++++ .../flat.set.modifiers/replace.pass.cpp | 72 ++ .../swap_exception.pass.cpp | 61 ++ .../flat.set.modifiers/swap_free.pass.cpp | 94 ++ .../flat.set.modifiers/swap_member.pass.cpp | 92 ++ .../flat.set/flat.set.observers/comp.pass.cpp | 72 ++ .../flat.set.operations/contains.pass.cpp | 69 ++ .../contains_transparent.pass.cpp | 70 ++ .../flat.set.operations/count.pass.cpp | 69 ++ .../count_transparent.pass.cpp | 71 ++ .../flat.set.operations/equal_range.pass.cpp | 77 ++ .../equal_range_transparent.pass.cpp | 97 ++ .../flat.set.operations/find.pass.cpp | 53 ++ .../find_transparent.pass.cpp | 88 ++ .../flat.set.operations/lower_bound.pass.cpp | 70 ++ .../lower_bound_transparent.pass.cpp | 94 ++ .../flat.set.operations/upper_bound.pass.cpp | 71 ++ .../upper_bound_transparent.pass.cpp | 93 ++ .../container.adaptors/flat.set/helpers.h | 294 ++++++ .../flat.set/incomplete_type.pass.cpp | 33 + .../flat.set/op_compare.pass.cpp | 105 +++ .../flat.set/types.compile.pass.cpp | 94 ++ 82 files changed, 8453 insertions(+) create mode 100644 libcxx/include/__flat_set/flat_set.h create mode 100644 libcxx/include/flat_set create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/helpers.h create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8dac823503d73f..75acf9f7899ff6 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -367,6 +367,7 @@ set(files __flat_map/sorted_equivalent.h __flat_map/sorted_unique.h __flat_map/utils.h + __flat_set/flat_set.h __format/buffer.h __format/concepts.h __format/container_adaptor.h @@ -986,6 +987,7 @@ set(files fenv.h filesystem flat_map + flat_set float.h format forward_list diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h new file mode 100644 index 00000000000000..c920632c453bf5 --- /dev/null +++ b/libcxx/include/__flat_set/flat_set.h @@ -0,0 +1,853 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FLAT_set_FLAT_SET_H +#define _LIBCPP___FLAT_set_FLAT_SET_H + +#include <__algorithm/lexicographical_compare_three_way.h> +#include <__algorithm/min.h> +#include <__algorithm/ranges_adjacent_find.h> +#include <__algorithm/ranges_equal.h> +#include <__algorithm/ranges_inplace_merge.h> +#include <__algorithm/ranges_lower_bound.h> +#include <__algorithm/ranges_partition_point.h> +#include <__algorithm/ranges_sort.h> +#include <__algorithm/ranges_unique.h> +#include <__algorithm/ranges_upper_bound.h> +#include <__algorithm/remove_if.h> +#include <__assert> +#include <__compare/synth_three_way.h> +#include <__concepts/swappable.h> +#include <__config> +#include <__cstddef/byte.h> +#include <__cstddef/ptrdiff_t.h> +#include <__flat_map/sorted_unique.h> +#include <__functional/invoke.h> +#include <__functional/is_transparent.h> +#include <__functional/operations.h> +#include <__fwd/vector.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/ranges_iterator_traits.h> +#include <__iterator/reverse_iterator.h> +#include <__memory/allocator_traits.h> +#include <__memory/uses_allocator.h> +#include <__memory/uses_allocator_construction.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/container_compatible_range.h> +#include <__ranges/drop_view.h> +#include <__ranges/from_range.h> +#include <__ranges/ref_view.h> +#include <__ranges/size.h> +#include <__ranges/subrange.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/container_traits.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_allocator.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_same.h> +#include <__utility/exception_guard.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include <__utility/scope_guard.h> +#include <__vector/vector.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template , class _KeyContainer = vector<_Key>> +class flat_set { + template + friend class flat_set; + + static_assert(is_same_v<_Key, typename _KeyContainer::value_type>); + static_assert(!is_same_v<_KeyContainer, std::vector>, "vector is not a sequence container"); + +public: + // types + using key_type = _Key; + using value_type = _Key; + using key_compare = __type_identity_t<_Compare>; + using value_compare = _Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename _KeyContainer::size_type; + using difference_type = typename _KeyContainer::difference_type; + using iterator = typename _KeyContainer::const_iterator; + using const_iterator = iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using container_type = _KeyContainer; + +private: + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = + uses_allocator::value; + + _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; + +public: + // [flat.set.cons], construct/copy/destroy + _LIBCPP_HIDE_FROM_ABI + flat_set() noexcept(is_nothrow_default_constructible_v<_KeyContainer> && is_nothrow_default_constructible_v<_Compare>) + : __keys_(), __compare_() {} + + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other) noexcept( + is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : __keys_(std::move(__other.__keys_)), __compare_(std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + // gcc does not like the `throw` keyword in a conditionally noexcept function + if constexpr (!(is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>)) { + throw; + } +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const key_compare& __comp) : __keys_(), __compare_(__comp) {} + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + __sort_and_unique(); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(), __compare_(__comp) { + insert(__first, __last); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(__first, __last), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg) + : flat_set(from_range, std::forward<_Range>(__rg), key_compare()) {} + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp) : flat_set(__comp) { + insert_range(std::forward<_Range>(__rg)); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(__il.begin(), __il.end(), __comp) {} + + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : flat_set(__ctor_uses_allocator_tag{}, __alloc, std::move(__other.__keys_), std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + throw; +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(sorted_unique, __first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, + _InputIterator __first, + _InputIterator __last, + const key_compare& __comp, + const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(sorted_unique, __first, __last); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert_range(std::forward<_Range>(__rg)); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert_range(std::forward<_Range>(__rg)); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(initializer_list __il) { + clear(); + insert(__il); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(flat_set&& __other) noexcept( + is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_Compare>) { + // No matter what happens, we always want to clear the other container before returning + // since we moved from it + auto __clear_other_guard = std::__make_scope_guard([&]() noexcept { __other.clear() /* noexcept */; }); + { + // If an exception is thrown, we have no choice but to clear *this to preserve invariants + auto __on_exception = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__other.__keys_); + __compare_ = std::move(__other.__compare_); + __on_exception.__complete(); + } + return *this; + } + + // iterators + _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + + _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return begin(); } + _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return end(); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + // [flat.set.capacity], capacity + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __keys_.empty(); } + + _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __keys_.size(); } + + _LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept { return __keys_.max_size(); } + + // [flat.set.modifiers], modifiers + template + _LIBCPP_HIDE_FROM_ABI pair emplace(_Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __try_emplace(std::forward<_Args>(__args)...); + } else { + return __try_emplace(_Key(std::forward<_Args>(__args)...)); + } + } + + template + _LIBCPP_HIDE_FROM_ABI iterator emplace_hint(const_iterator __hint, _Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __emplace_hint(std::move(__hint), std::forward<_Args>(__args)...); + } else { + return __emplace_hint(std::move(__hint), _Key(std::forward<_Args>(__args)...)); + } + } + + _LIBCPP_HIDE_FROM_ABI pair insert(const value_type& __x) { return emplace(__x); } + + _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { + return emplace(std::forward<_Kp>(__x)); + } + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, const value_type& __x) { + return emplace_hint(__hint, __x); + } + + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, value_type&& __x) { + return emplace_hint(__hint, std::move(__x)); + } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { + return emplace_hint(__hint, std::forward<_Kp>(__x)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, _InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { + if constexpr (ranges::sized_range<_Range>) { + __reserve(ranges::size(__range)); + } + + __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + } + + _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } + + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, initializer_list __il) { + insert(sorted_unique, __il.begin(), __il.end()); + } + + _LIBCPP_HIDE_FROM_ABI container_type extract() && { + auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; }); + auto __ret = std::move(__keys_); + return __ret; + } + + _LIBCPP_HIDE_FROM_ABI void replace(container_type&& __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys), "Either the key container is not sorted or it contains duplicates"); + auto __guard = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__keys); + __guard.__complete(); + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __position) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_iter = __keys_.erase(__position); + __on_failure.__complete(); + return __key_iter; + } + + // The following overload is the same as the iterator overload + // iterator erase(const_iterator __position); + + _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __x) { + auto __iter = find(__x); + if (__iter != end()) { + erase(__iter); + return 1; + } + return 0; + } + + template + requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + !is_convertible_v<_Kp &&, const_iterator>) + _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { + auto [__first, __last] = equal_range(__x); + auto __res = __last - __first; + erase(__first, __last); + return __res; + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_it = __keys_.erase(__first, __last); + __on_failure.__complete(); + return __key_it; + } + + _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __y) noexcept { + // warning: The spec has unconditional noexcept, which means that + // if any of the following functions throw an exception, + // std::terminate will be called. + // This is discussed in P2767, which hasn't been voted on yet. + ranges::swap(__compare_, __y.__compare_); + ranges::swap(__keys_, __y.__keys_); + } + + _LIBCPP_HIDE_FROM_ABI void clear() noexcept { __keys_.clear(); } + + // observers + _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __compare_; } + _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __compare_; } + + // set operations + _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __x) { return __find_impl(*this, __x); } + + _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { + return __find_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { + return __find_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { + return contains(__x) ? 1 : 0; + } + + _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { + return find(__x) != end(); + } + + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) { + return __equal_range_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) const { + return __equal_range_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { + return __equal_range_impl(*this, __x); + } + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { + return __equal_range_impl(*this, __x); + } + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const flat_set& __x, const flat_set& __y) { + return ranges::equal(__x, __y); + } + + friend _LIBCPP_HIDE_FROM_ABI auto operator<=>(const flat_set& __x, const flat_set& __y) { + return std::lexicographical_compare_three_way( + __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); + } + + friend _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __x, flat_set& __y) noexcept { __x.swap(__y); } + +private: + struct __ctor_uses_allocator_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_tag() = default; + }; + struct __ctor_uses_allocator_empty_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_empty_tag() = default; + }; + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), + __compare_(std::forward<_CompArg>(__comp)...) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc)), + __compare_(std::forward<_CompArg>(__comp)...) {} + + _LIBCPP_HIDE_FROM_ABI bool __is_sorted_and_unique(auto&& __key_container) const { + auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) { return !__compare_(__x, __y); }; + return ranges::adjacent_find(__key_container, __greater_or_equal_to) == ranges::end(__key_container); + } + + // This function is only used in constructors. So there is not exception handling in this function. + // If the function exits via an exception, there will be no flat_set object constructed, thus, there + // is no invariant state to preserve + _LIBCPP_HIDE_FROM_ABI void __sort_and_unique() { + ranges::sort(__keys_, __compare_); + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } else { + for (; __first != __last; ++__first) { + __keys_.insert(__keys_.end(), *__first); + } + } + if (size() != __old_size) { + if constexpr (!_WasSorted) { + ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); + } else { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__is_sorted_and_unique(__keys_ | ranges::views::drop(__old_size)), + "Either the key container is not sorted or it contains duplicates"); + } + ranges::inplace_merge(__keys_.begin(), __keys_.begin() + __old_size, __keys_.end(), __compare_); + + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + __on_failure.__complete(); + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __find_impl(_Self&& __self, const _Kp& __key) { + auto __it = __self.lower_bound(__key); + auto __last = __self.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return __last; + } + return __it; + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __equal_range_impl(_Self&& __self, const _Kp& __key) { + auto __it = ranges::lower_bound(__self.__keys_, __key, __self.__compare_); + auto __last = __self.__keys_.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return std::make_pair(__it, __it); + } + return std::make_pair(__it, std::next(__it)); + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_exact_pos(const_iterator __it, _KeyArg&& __key) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { + if constexpr (!__container_traits<_KeyContainer>::__emplacement_has_strong_exception_safety_guarantee) { + clear() /* noexcept */; + } + }); + auto __key_it = __keys_.emplace(__it, std::forward<_KeyArg>(__key)); + __on_failure.__complete(); + return __key_it; + } + + template + _LIBCPP_HIDE_FROM_ABI pair __try_emplace(_Kp&& __key) { + auto __it = lower_bound(__key); + if (__it == end() || __compare_(__key, *__it)) { + return pair(__emplace_exact_pos(__it, std::forward<_Kp>(__key)), true); + } else { + return pair(std::move(__it), false); + } + } + + template + _LIBCPP_HIDE_FROM_ABI bool __is_hint_correct(const_iterator __hint, _Kp&& __key) { + if (__hint != cbegin() && !__compare_(*(__hint - 1), __key)) { + return false; + } + if (__hint != cend() && __compare_(*__hint, __key)) { + return false; + } + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint(const_iterator __hint, _Kp&& __key) { + if (__is_hint_correct(__hint, __key)) { + if (__hint == cend() || __compare_(__key, *__hint)) { + return __emplace_exact_pos(__hint, std::forward<_Kp>(__key)); + } else { + // key equals + return __hint; + } + } else { + return __try_emplace(std::forward<_Kp>(__key)).first; + } + } + + _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __size) { + if constexpr (requires { __keys_.reserve(__size); }) { + __keys_.reserve(__size); + } + } + + template + friend typename flat_set<_Key2, _Compare2, _KeyContainer2>::size_type + erase_if(flat_set<_Key2, _Compare2, _KeyContainer2>&, _Predicate); + + _KeyContainer __keys_; + _LIBCPP_NO_UNIQUE_ADDRESS key_compare __compare_; + + struct __key_equiv { + _LIBCPP_HIDE_FROM_ABI __key_equiv(key_compare __c) : __comp_(__c) {} + _LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const { + return !__comp_(__x, __y) && !__comp_(__y, __x); + } + key_compare __comp_; + }; +}; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(_KeyContainer, _Compare = _Compare()) -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(_KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(_KeyContainer, _Compare, _Allocator) -> flat_set; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare = _Compare()) + -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(sorted_unique_t, _KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare, _Allocator) + -> flat_set; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(_InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >, + class _Allocator = allocator, + class = __enable_if_t::value && __is_allocator<_Allocator>::value>> +flat_set(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> flat_set< + ranges::range_value_t<_Range>, + _Compare, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template ::value>> +flat_set(from_range_t, _Range&&, _Allocator) -> flat_set< + ranges::range_value_t<_Range>, + less>, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template +struct uses_allocator, _Allocator> + : bool_constant> {}; + + template + _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type + erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; + } + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FLAT_set_FLAT_SET_H diff --git a/libcxx/include/flat_set b/libcxx/include/flat_set new file mode 100644 index 00000000000000..d03645fafafdba --- /dev/null +++ b/libcxx/include/flat_set @@ -0,0 +1,59 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_FLAT_SET +#define _LIBCPP_FLAT_SET + +/* + Header synopsis + +#include // see [compare.syn] +#include // see [initializer.list.syn] + +namespace std { + // [flat.set], class template flat_set + template, class KeyContainer = vector> + class flat_set; + + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + + template + struct uses_allocator, Allocator>; + + // [flat.set.erasure], erasure for flat_set + template + typename flat_set::size_type + erase_if(flat_set& c, Predicate pred); +} +*/ + +#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +# include <__cxx03/__config> +#else +# include <__config> + +# if _LIBCPP_STD_VER >= 23 +# include <__flat_map/sorted_unique.h> +# include <__flat_set/flat_set.h> +# endif + +// for feature-test macros +# include + +// standard required includes +# include +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif +#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) + +#endif // _LIBCPP_FLAT_SET diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4bae02137b37b2..abc351d5923963 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1263,6 +1263,17 @@ module std [system] { export * } + module flat_set { + module flat_set { + header "__flat_set/flat_set.h" + export std.vector.vector + export std.vector.fwd + } + + header "flat_set" + export * + } + module format { module buffer { header "__format/buffer.h" diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp new file mode 100644 index 00000000000000..204df1d681af1b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m; + ASSERT_SAME_TYPE(decltype(m.empty()), bool); + ASSERT_NOEXCEPT(m.empty()); + assert(m.empty()); + assert(std::as_const(m).empty()); + m = {1}; + assert(!m.empty()); + m.clear(); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp new file mode 100644 index 00000000000000..161fe533eabacb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include + +void f() { + std::flat_set c; + c.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp new file mode 100644 index 00000000000000..cd7f424e00ece2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type max_size() const noexcept; + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_allocator.h" +#include "test_macros.h" + +int main(int, char**) { + { + using A1 = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= 10); + LIBCPP_ASSERT(c.max_size() == 10); + } + { + using A = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + LIBCPP_ASSERT(c.max_size() == max_dist); + } + { + typedef std::flat_set C; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + assert(c.max_size() <= alloc_max_size(std::allocator())); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp new file mode 100644 index 00000000000000..7c156e95ecb1c8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type size() const noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using M = std::flat_set, KeyContainer>; + using S = typename M::size_type; + { + const M m = {1, 1, 4, 5, 5}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 3); + } + { + const M m = {1}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 1); + } + { + const M m; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 0); + } + { + M m; + S s = 1000000; + for (auto i = 0u; i < s; ++i) { + m.emplace(i); + } + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == s); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp new file mode 100644 index 00000000000000..acc0817d7cac4d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// explicit flat_set(const Allocator& a); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // explicit + using M = std::flat_set, std::vector>>; + + static_assert(std::is_constructible_v>); + static_assert(!std::is_convertible_v, M>); + } + { + using A = test_allocator; + using M = std::flat_set, std::vector>>; + M m(A(0, 5)); + assert(m.empty()); + assert(m.begin() == m.end()); + auto v = std::move(m).extract(); + assert(v.get_allocator().get_id() == 5); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp new file mode 100644 index 00000000000000..7f75f1e1611e3b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(initializer_list il); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m = {8, 10}; + assert(m.size() == 2); + m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + int expected[] = {1, 2, 3, 4, 5, 6}; + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + } + { + M m = {10, 8}; + assert(m.size() == 2); + m = {3}; + int expected[] = {3}; + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp new file mode 100644 index 00000000000000..b3bee18f5a936b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(const key_compare& comp); +// template +// flat_set(const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + auto m = std::flat_set(C(3)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(3)); + } + { + // The one-argument ctor is explicit. + using C = test_less; + static_assert(std::is_constructible_v, C>); + static_assert(!std::is_convertible_v>); + + static_assert(std::is_constructible_v, std::less>); + static_assert(!std::is_convertible_v, std::flat_set>); + } + { + using C = test_less; + using A1 = test_allocator; + auto m = std::flat_set>(C(4), A1(5)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + { + // explicit(false) + using C = test_less; + using A1 = test_allocator; + std::flat_set> m = {C(4), A1(5)}; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp new file mode 100644 index 00000000000000..3d1e6240c952e8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -0,0 +1,158 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(container_type key_cont, const key_compare& comp = key_compare()); +// template +// flat_set(const container_type& key_cont, const Allocator& a); +// template +// flat_set(const container_type& key_cont, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(container_type) + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + + // explicit + static_assert(std::is_constructible_v&>); + static_assert(!ImplicitlyConstructible&>); + } + { + // flat_set(container_type) + // move-only + MoveOnly expected[] = {3, 2, 1}; + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks; + ks.push_back(1); + ks.push_back(3); + ks.push_back(2); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(container_type) + // container's allocator is used + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(5)); + } + { + // flat_set(container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + + // explicit + static_assert(std::is_constructible_v&, const C&>); + static_assert(!ImplicitlyConstructible&, const C&>); + } + { + // flat_set(container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(ks, A(4)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , const Allocator&) + // explicit(false) + using A = test_allocator; + using M = std::flat_set, std::deque>; + static_assert(ImplicitlyConstructible&, const A&>); + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + M m = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4), A(5)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + auto m_copy = m; + auto keys = std::move(m_copy).extract(); + assert(keys.get_allocator() == A(5)); + + // explicit(false) + static_assert(ImplicitlyConstructible&, const A&>); + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + keys = std::move(m2).extract(); + assert(keys.get_allocator() == A(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp new file mode 100644 index 00000000000000..f1dbc955e1b0de --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(-2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp new file mode 100644 index 00000000000000..59fb9d0a38366f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M(mo, test_allocator(3)); + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(3)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp new file mode 100644 index 00000000000000..169b469f3bca68 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& s); + +// Validate whether the container can be copy-assigned (move-assigned, swapped) +// with an ADL-hijacking operator& + +#include +#include + +#include "test_macros.h" +#include "operator_hijacker.h" + +void test() { + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp new file mode 100644 index 00000000000000..cdd5045f4bb9f7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // test_allocator is not propagated + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M({{3, 4, 5}}, C(3), test_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + // other_allocator is propagated + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = M({3, 4, 5}, C(3), other_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + { + // comparator is copied and invariant is preserved + using M = std::flat_set>; + M mo = M({1, 2}, std::less()); + M m = M({1, 2}, std::greater()); + assert(m.key_comp()(2, 1) == true); + assert(m != mo); + m = mo; + assert(m.key_comp()(2, 1) == false); + assert(m == mo); + } + { + // self-assignment + using M = std::flat_set; + M m = {{1, 2}}; + m = static_cast(m); + assert((m == M{{1, 2}})); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp new file mode 100644 index 00000000000000..5db8c4ca722466 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Test CTAD on cases where deduction should fail. + +#include +#include +#include +#include +#include + +struct NotAnAllocator { + friend bool operator<(NotAnAllocator, NotAnAllocator) { return false; } +}; + +template +concept CanDeductFlatSet = requires { std::flat_set{std::declval()...}; }; + +static_assert(CanDeductFlatSet, std::vector>); + +// cannot deduce Key and T from nothing +static_assert(!CanDeductFlatSet<>); + +// cannot deduce Key and T from just (KeyContainer), even if it's a container of pairs +static_assert(!CanDeductFlatSet>>); + +// cannot deduce Key and T from just (KeyContainer, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>>); + +// cannot deduce Key and T from just (Compare) +static_assert(!CanDeductFlatSet>); + +// cannot deduce Key and T from just (Compare, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>); + +// cannot deduce Key and T from just (Allocator) +static_assert(!CanDeductFlatSet>); + +// cannot convert from some arbitrary unrelated type +static_assert(!CanDeductFlatSet); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp new file mode 100644 index 00000000000000..612e64a7c42f23 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -0,0 +1,341 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "deduction_guides_sfinae_checks.h" +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_copy() { + { + std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set s(source); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s{source}; // braces instead of parens + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s(source, std::allocator()); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } +} + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(ks, vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(ks, vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_iter_iter() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m(std::begin(arr), std::end(arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) + static_assert(std::is_same_v>); + assert(s.size() == 3); + } +} + +void test_iter_iter_compare() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m(std::begin(arr), std::end(arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } +} + +void test_initializer_list() { + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } + { + using M = std::flat_set; + M m; + std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + assert(s[m] == m); + } +} + +void test_initializer_list_compare() { + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } +} + +void test_from_range() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(std::from_range, r); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +void test_from_range_compare() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(std::from_range, r, std::greater()); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +int main(int, char**) { + // Each test function also tests the sorted_unique-prefixed and allocator-suffixed overloads. + test_copy(); + test_containers(); + test_containers_compare(); + test_iter_iter(); + test_iter_iter_compare(); + test_initializer_list(); + test_initializer_list_compare(); + test_from_range(); + test_from_range_compare(); + + AssociativeContainerDeductionGuidesSfinaeAway>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp new file mode 100644 index 00000000000000..df8d6d885ee524 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + const int expected[] = {1, 2, 3, INT_MAX}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + const int expected[] = {INT_MAX, 3, 2, 1}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +int main(int, char**) { + test_containers(); + test_containers_compare(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp new file mode 100644 index 00000000000000..64b0bfcb383a72 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + std::flat_set m; + assert(m.empty()); + } + { + // explicit(false) + std::flat_set m = {}; + assert(m.empty()); + } + { + std::flat_set>> m; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp().default_constructed_); + } + { + using A1 = explicit_allocator; + using A2 = explicit_allocator; + { + std::flat_set> m; + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + { + A1 a1; + std::flat_set> m(a1); + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp new file mode 100644 index 00000000000000..b4a3b6de205a31 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set() +// noexcept( +// is_nothrow_default_constructible_v && +// is_nothrow_default_constructible_v); + +// This tests a conforming extension + +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +int main(int, char**) { +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp new file mode 100644 index 00000000000000..c0d315c0ce74b4 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// ~flat_set(); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingDtorComp { + bool operator()(const auto&, const auto&) const; + ~ThrowingDtorComp() noexcept(false) {} +}; + +int main(int, char**) { + { + using C = std::flat_set; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::vector>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::deque>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(!std::is_nothrow_destructible_v); + C c; + } +#endif // _LIBCPP_VERSION + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp new file mode 100644 index 00000000000000..cd2319e91f760d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -0,0 +1,151 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(initializer_list il, const key_compare& comp = key_compare()); +// template +// flat_set(initializer_list il, const Alloc& a); +// template +// flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +#include "../../../test_compare.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + } + + int expected[] = {1, 2, 3, 5}; + { + // flat_set(initializer_list); + using M = std::flat_set; + std::initializer_list il = {5, 2, 2, 3, 1, 3}; + M m(il); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + // explicit(false) + using M = std::flat_set; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + using M = std::flat_set, std::deque>>; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + { + using A = explicit_allocator; + { + // flat_set(initializer_list); + // different comparator + using M = std::flat_set>; + M m = {1, 2, 3}; + assert(m.size() == 1); + LIBCPP_ASSERT(*m.begin() == 1); + assert(m.key_comp().default_constructed_); + } + { + // flat_set(initializer_list, const Allocator&); + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + } + { + // flat_set(initializer_list, const key_compare&); + using C = test_less; + using M = std::flat_set; + auto m = M({5, 2, 2, 3, 1, 3}, C(10)); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + assert(m.key_comp() == C(10)); + + // explicit(false) + M m2 = {{5, 2, 2, 1, 3, 3}, C(10)}; + assert(m2 == m); + assert(m2.key_comp() == C(10)); + } + { + // flat_set(initializer_list, const key_compare&); + // Sorting uses the comparator that was passed in + using M = std::flat_set, std::deque>>; + auto m = M({5, 2, 2, 1, 3, 1}, std::greater()); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + assert(m.key_comp()(2, 1) == true); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using A = explicit_allocator; + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, {}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp new file mode 100644 index 00000000000000..65eebc21a66c4c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(InputIterator first, InputIterator last, const Allocator& a); +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(InputIterator , InputIterator) + // cpp17_input_iterator + using M = std::flat_set; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)}; + assert(m2 == m); + } + { + // flat_set(InputIterator , InputIterator) + // greater + using M = std::flat_set, std::deque>>; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(InputIterator , InputIterator) + // Test when the operands are of array type (also contiguous iterator type) + using M = std::flat_set, std::vector>>; + auto m = M(ar, ar); + assert(m.empty()); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&) + using C = test_less; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {ar, ar + 9, C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + auto m = M(ar, ar + 9, A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + M m = {ar, ar + 9, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {ar, ar + 9, {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp new file mode 100644 index 00000000000000..69b340ad09fe15 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A(7)); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A(7)); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().get_id() == test_alloc_base::moved_value); + } + { + using C = test_less; + using A = min_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A()); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A()); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A()); + } + { + // A moved-from flat_set maintains its class invariant in the presence of moved-from comparators. + using M = std::flat_set>; + M mo = M({1, 2, 3}, std::less()); + M m = std::move(mo); + assert(m.size() == 3); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.key_comp()(1, 2) == true); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + LIBCPP_ASSERT(m.key_comp()(1, 2) == true); + LIBCPP_ASSERT(mo.empty()); + mo.insert({1, 2, 3}); // insert has no preconditions + assert(m == mo); + } + { + // moved-from object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m1.size() == 0); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp new file mode 100644 index 00000000000000..fc7f68d8c967ad --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + int expected[] = {1, 2, 3}; + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + auto mo = M(expected, expected + 3, C(5), A(7)); + auto m = M(std::move(mo), A(3)); + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(3)); + assert(std::ranges::equal(keys, expected )); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A(7)); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2(std::move(m1), std::allocator{}); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp new file mode 100644 index 00000000000000..b16dc38dd40285 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{4, 5})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + m = std::move(mo); + assert((m == M{5, 4, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A()); + assert(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp new file mode 100644 index 00000000000000..50817f4be8a812 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); +// Preserves the class invariant for the moved-from flat_set. + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +int main(int, char**) { + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp new file mode 100644 index 00000000000000..86f3568f0d67a6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&& c) +// noexcept( +// is_nothrow_move_assignable::value && +// is_nothrow_move_assignable::value && +// is_nothrow_copy_assignable::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_macros.h" + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp new file mode 100644 index 00000000000000..17e4e40387606c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// flat_set(flat_set&& s); +// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +int main(int, char**) { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp new file mode 100644 index 00000000000000..49d1151fd8a993 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&) +// noexcept(is_nothrow_move_constructible::value && +// is_nothrow_move_constructible::value && +// is_nothrow_copy_constructible::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp new file mode 100644 index 00000000000000..785718d2eed333 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -0,0 +1,322 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +// Test various constructors with pmr + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // flat_set(const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::polymorphic_allocator pa = &mr; + auto m1 = M(pa); + assert(m1.empty()); + assert(std::move(m1).extract().get_allocator() == pa); + auto m2 = M(&mr); + assert(m2.empty()); + assert(std::move(m2).extract().get_allocator() == pa); + } + { + // flat_set(const key_compare& comp, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::greater()); + assert(vm[0] == M{}); + assert(vm[0].key_comp()(2, 1) == true); + assert(vm[0].value_comp()(2, 1) == true); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + // const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + assert(ks.get_allocator().resource() != &mr); + vm.emplace_back(ks); + assert(ks.size() == 9); // ks' value is unchanged, since it was an lvalue above + assert((vm[0] == M{1, 2, 3})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const flat_set&, const allocator_type&); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, C(5), &mr1); + M m = {mo, &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + auto keys = std::move(m).extract(); + assert((keys == std::pmr::vector{1, 2, 3})); + assert(keys.get_allocator().resource() == &mr2); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + auto keys2 = std::move(mo).extract(); + assert((keys2 == std::pmr::vector{1, 2, 3})); + assert(keys2.get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set&, const allocator_type&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::vector vs; + M m = {1, 2, 3}; + vs.push_back(m); + assert(vs[0] == m); + } + { + // flat_set& operator=(const flat_set& m); + // pmr allocator is not propagated + using M = std::flat_set, std::pmr::deque>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, &mr1); + M m = M({4, 5}, &mr2); + m = mo; + assert((m == M{1, 2, 3})); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // mo is unchanged + assert((mo == M{1, 2, 3})); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set& m); + using C = test_less; + std::pmr::monotonic_buffer_resource mr; + using M = std::flat_set>; + auto mo = M({1, 2, 3}, C(5), &mr); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert((m == M{1, 2, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator().resource() == std::pmr::get_default_resource()); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert((mo == M{1, 2, 3})); + auto kso = std::move(mo).extract(); + assert(kso.get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il, C(5)); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + assert(vm[0].key_comp() == C(5)); + } + { + // flat_set(InputIterator first, InputIterator last, const Allocator& a); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // cpp17 iterator + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(ar, ar); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(flat_set&&, const allocator_type&); + int expected[] = {1, 2, 3}; + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 3, 1, 2}, C(5), &mr1); + M m = {std::move(mo), &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + assert(std::equal(m.begin(), m.end(), expected, expected + 3)); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(flat_set&&, const allocator_type&); + using M = std::flat_set, std::pmr::deque>; + std::pmr::vector vs; + M m = {1, 3, 1, 2}; + vs.push_back(std::move(m)); + assert((std::move(vs[0]).extract() == std::pmr::deque{1, 2, 3})); + } + { + // flat_set& operator=(flat_set&&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = + M({"short", "very long string that definitely won't fit in the SSO buffer and therefore becomes empty on move"}, + &mr1); + M m = M({"don't care"}, &mr2); + m = std::move(mo); + assert(m.size() == 2); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.begin()->get_allocator().resource() == &mr2); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + mo.insert("foo"); + assert(mo.begin()->get_allocator().resource() == &mr1); + } + { + // flat_set(from_range_t, R&&, const Alloc&); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // input_range + using M = std::flat_set, std::pmr::vector>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(ar, ar)); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 2, 4, 10}; + vm.emplace_back(std::sorted_unique, ks); + assert(!ks.empty()); // it was an lvalue above + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, const container_type& key_cont,const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks({1, 2, 4, 10}, &mr); + vm.emplace_back(std::sorted_unique, ks); + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp new file mode 100644 index 00000000000000..bb9f99c228bfec --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -0,0 +1,173 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// flat_set(from_range_t, R&&) +// template R> +// flat_set(from_range_t, R&&, const key_compare&) +// template R, class Alloc> +// flat_set(from_range_t, R&&, const Alloc&); +// template R, class Alloc> +// flat_set(from_range_t, R&&, const key_compare&, const Alloc&); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +// test constraint container-compatible-range + +template +using RangeOf = std::ranges::subrange; +using Set = std::flat_set; + +static_assert(std::is_constructible_v>); +static_assert(std::is_constructible_v>); +static_assert(!std::is_constructible_v>>); + +static_assert(std::is_constructible_v, std::less>); +static_assert(std::is_constructible_v, std::less>); +static_assert(!std::is_constructible_v>, std::less>); + +static_assert(std::is_constructible_v, std::allocator>); +static_assert(std::is_constructible_v, std::allocator>); +static_assert(!std::is_constructible_v>, std::allocator>); + +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert( + !std:: + is_constructible_v>, std::less, std::allocator>); + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(from_range_t, R&&) + // input_range && !common + using M = std::flat_set; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))}; + assert(m2 == m); + } + { + // flat_set(from_range_t, R&&) + // greater + using M = std::flat_set, std::deque>>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(from_range_t, R&&) + // contiguous range + using M = std::flat_set; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9)); + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(from_range_t, R&&, const key_compare&) + using C = test_less; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {std::from_range, R(ar, ar + 9), C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp new file mode 100644 index 00000000000000..2d442d49667bd0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(sorted_unique_t, container_type key_cont, const key_compare& comp = key_compare()); +// +// template +// flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); +// template +// flat_set(sorted_unique_t, const container_type& key_cont, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, container_type) + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + auto ks2 = ks; + + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + + // explicit(false) + M m2 = {std::sorted_unique, std::move(ks2)}; + assert(m == m2); + } + { + // flat_set(sorted_unique_t, container_type) + // non-default container, comparator and allocator type + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks = {10, 4, 2, 1}; + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + } + { + // flat_set(sorted_unique_t, container_type) + // allocator copied into the containers + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + assert(std::move(m).extract().get_allocator() == A(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + + auto m = M(std::sorted_unique, ks, C(4)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, C(4)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 2, 4, 10}; + auto m = M(std::sorted_unique, ks, C(4), A(5)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + assert(M(m).extract().get_allocator() == A(5)); + + // explicit(false) + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + assert(std::move(m2).extract().get_allocator() == A(5)); + } + { + // flat_set(sorted_unique_t, container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, ks, A(6)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 4, 10})); + assert(M(m).extract().get_allocator() == A(6)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, A(6)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp new file mode 100644 index 00000000000000..01956a78c7f48d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t s, initializer_list il, +// const key_compare& comp = key_compare()) +// template +// flat_set(sorted_unique_t, initializer_list il, const Alloc& a); +// template +// flat_set(sorted_unique_t, initializer_list il, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +std::initializer_list il = {1, 2, 4, 5}; + +const auto il1 = il; +const auto il2 = il; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + } + + { + // flat_set(sorted_unique_t, initializer_list); + using M = std::flat_set; + auto m = M(std::sorted_unique, il1); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, il1}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + using M = std::flat_set>; + auto m = M(std::sorted_unique, il1, std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, il1, std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + std::initializer_list il4{5, 4, 2, 1}; + auto m = M(std::sorted_unique, il4, std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, initializer_list, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + auto m = M(std::sorted_unique, il2, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, il2, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(std::sorted_unique, il2, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {std::sorted_unique, il2, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp new file mode 100644 index 00000000000000..b5229a84dd5133 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // cpp17_input_iterator + using M = std::flat_set; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // cpp_17_input_iterator + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + int ar[] = {5, 4, 2, 1}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[1] = {42}; + auto m = M(std::sorted_unique, ar, ar, C(5)); + assert(m.empty()); + assert(m.key_comp() == C(5)); + } + { + // flat_set(sorted_unique_t, InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, ar, ar + 4, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + int ar[] = {1, 2, 4, 5}; + M m = {std::sorted_unique, ar, ar + 4, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp new file mode 100644 index 00000000000000..134db83aef3cad --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "min_allocator.h" + +// Verify that `flat_set` (like `set`) does NOT support std::erase. +// +template +concept HasStdErase = requires(S& s, typename S::value_type x) { std::erase(s, x); }; +static_assert(HasStdErase>); +static_assert(!HasStdErase>); + +template +M make(std::initializer_list vals) { + M ret; + for (int v : vals) + ret.emplace(v); + return ret; +} + +template +void test0( + std::initializer_list vals, Pred p, std::initializer_list expected, std::size_t expected_erased_count) { + M s = make(vals); + ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p))); + assert(expected_erased_count == std::erase_if(s, p)); + assert(s == make(expected)); +} + +template +void test() { + // Test all the plausible signatures for this predicate. + auto is1 = [](typename S::const_reference v) { return v == 1; }; + auto is2 = [](typename S::value_type v) { return v == 2; }; + auto is3 = [](const typename S::value_type& v) { return v == 3; }; + auto is4 = [](auto v) { return v == 4; }; + auto True = [](const auto&) { return true; }; + auto False = [](auto&&) { return false; }; + + test0({}, is1, {}, 0); + + test0({1}, is1, {}, 1); + test0({1}, is2, {1}, 0); + + test0({1, 2}, is1, {2}, 1); + test0({1, 2}, is2, {1}, 1); + test0({1, 2}, is3, {1, 2}, 0); + + test0({1, 2, 3}, is1, {2, 3}, 1); + test0({1, 2, 3}, is2, {1, 3}, 1); + test0({1, 2, 3}, is3, {1, 2}, 1); + test0({1, 2, 3}, is4, {1, 2, 3}, 0); + + test0({1, 2, 3}, True, {}, 3); + test0({1, 2, 3}, False, {1, 2, 3}, 0); +} + +int main(int, char**) { + test>(); + test, std::vector>>>(); + test, std::vector>>>(); + test, std::deque>>>(); + test, std::deque>>>(); + test>(); + test>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp new file mode 100644 index 00000000000000..6bbe1ad4f01670 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -0,0 +1,128 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); +// If any member function in [flat.set.defn] exits via an exception, the invariant is restored. +// (This is not a member function, but let's respect the invariant anyway.) + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct Counter { + int c1, c2, throws; + void tick() { + c1 -= 1; + if (c1 == 0) { + c1 = c2; + throws += 1; + throw 42; + } + } +}; +Counter g_counter = {0, 0, 0}; + +struct ThrowingAssignment { + ThrowingAssignment(int i) : i_(i) {} + ThrowingAssignment(const ThrowingAssignment&) = default; + ThrowingAssignment& operator=(const ThrowingAssignment& rhs) { + g_counter.tick(); + i_ = rhs.i_; + g_counter.tick(); + return *this; + } + operator int() const { return i_; } + int i_; +}; + +struct ThrowingComparator { + bool operator()(const ThrowingAssignment& a, const ThrowingAssignment& b) const { + g_counter.tick(); + return a.i_ < b.i_; + } +}; + +struct ErasurePredicate { + bool operator()(const auto& x) const { return (3 <= x && x <= 5); } +}; + +int main(int, char**) { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + { + using M = std::flat_set; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + M m = M({1, 2, 3, 4, 5, 6, 7, 8}); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + + { + using M = std::flat_set>; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + std::deque container = {5, 6, 7, 8}; + container.insert(container.begin(), {1, 2, 3, 4}); + M m = M(std::move(container)); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp new file mode 100644 index 00000000000000..c07297a141ad10 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator begin() noexcept; +// const_iterator begin() const noexcept +// iterator end() noexcept; +// const_iterator end() const noexcept; +// +// const_iterator cbegin() const noexcept; +// const_iterator cend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.begin()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cbegin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.begin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(m.end()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cend()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.end()), typename M::const_iterator); + static_assert(noexcept(m.begin())); + static_assert(noexcept(cm.begin())); + static_assert(noexcept(m.cbegin())); + static_assert(noexcept(m.end())); + static_assert(noexcept(cm.end())); + static_assert(noexcept(m.cend())); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(std::distance(cm.begin(), cm.end()) == 4); + assert(std::distance(m.cbegin(), m.cend()) == 4); + typename M::iterator i; // default-construct + i = m.begin(); // move-assignment + typename M::const_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 1; j <= 4; ++j, ++i) { // pre-increment + assert(*i == j); // operator* + } + assert(i == m.end()); + for (int j = 4; j >= 1; --j) { + --i; // pre-decrement + assert((*i) == j); + } + assert(i == m.begin()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // N3644 testing + using C = std::flat_set; + C::iterator ii1{}, ii2{}; + C::iterator ii4 = ii1; + C::const_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp new file mode 100644 index 00000000000000..29441dcc57d40e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set iterators should be C++20 random access iterators + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using KI = typename KeyContainer::iterator; + using I = M::iterator; + using CI = M::const_iterator; + using RI = M::reverse_iterator; + using CRI = M::const_reverse_iterator; + + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + + M m = {1, 2, 3, 4}; + + I i1 = m.begin(); + I i2 = m.begin() + 1; + + assert(i1 == i1); + assert(!(i1 != i1)); + assert(i1 != i2); + assert(!(i1 == i2)); + assert(i1 < i2); + assert(!(i1 < i1)); + assert(i1 <= i1); + assert(i1 <= i2); + assert(!(i2 <= i1)); + assert(i2 > i1); + assert(!(i2 > i2)); + assert(i2 >= i1); + assert(i2 >= i2); + assert(!(i1 >= i2)); + + CI ci1 = m.cbegin(); + CI ci2 = m.cbegin() + 1; + assert(ci1 == ci1); + assert(!(ci1 != ci1)); + assert(ci1 != ci2); + assert(!(ci1 == ci2)); + assert(ci1 < ci2); + assert(!(ci1 < ci1)); + assert(ci1 <= ci1); + assert(ci1 <= ci2); + assert(!(ci2 <= ci1)); + assert(ci2 > ci1); + assert(!(ci2 > ci2)); + assert(ci2 >= ci1); + assert(ci2 >= ci2); + assert(!(ci1 >= ci2)); + + RI ri1 = m.rbegin(); + RI ri2 = m.rbegin() + 1; + assert(ri1 == ri1); + assert(!(ri1 != ri1)); + assert(ri1 != ri2); + assert(!(ri1 == ri2)); + assert(ri1 < ri2); + assert(!(ri1 < ri1)); + assert(ri1 <= ri1); + assert(ri1 <= ri2); + assert(!(ri2 <= ri1)); + assert(ri2 > ri1); + assert(!(ri2 > ri2)); + assert(ri2 >= ri1); + assert(ri2 >= ri2); + assert(!(ri1 >= ri2)); + + CRI cri1 = m.crbegin(); + CRI cri2 = m.crbegin() + 1; + assert(cri1 == cri1); + assert(!(cri1 != cri1)); + assert(cri1 != cri2); + assert(!(cri1 == cri2)); + assert(cri1 < cri2); + assert(!(cri1 < cri1)); + assert(cri1 <= cri1); + assert(cri1 <= cri2); + assert(!(cri2 <= cri1)); + assert(cri2 > cri1); + assert(!(cri2 > cri2)); + assert(cri2 >= cri1); + assert(cri2 >= cri2); + assert(!(cri1 >= cri2)); + + if constexpr (std::three_way_comparable) { + static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::same_as I()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as RI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + + assert(i1 <=> i1 == std::strong_ordering::equivalent); + assert(i1 <=> i2 == std::strong_ordering::less); + assert(i2 <=> i1 == std::strong_ordering::greater); + + assert(ci1 <=> ci1 == std::strong_ordering::equivalent); + assert(ci1 <=> ci2 == std::strong_ordering::less); + assert(ci2 <=> ci1 == std::strong_ordering::greater); + + assert(ri1 <=> ri1 == std::strong_ordering::equivalent); + assert(ri1 <=> ri2 == std::strong_ordering::less); + assert(ri2 <=> ri1 == std::strong_ordering::greater); + + assert(cri1 <=> cri1 == std::strong_ordering::equivalent); + assert(cri1 <=> cri2 == std::strong_ordering::less); + assert(cri2 <=> cri1 == std::strong_ordering::greater); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp new file mode 100644 index 00000000000000..35b45b6e797233 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator, const_iterator, reverse_iterator, const_reverse_iterator + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + using I = C::iterator; + using CI = C::const_iterator; + using RI = C::reverse_iterator; + using CRI = C::const_reverse_iterator; + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp new file mode 100644 index 00000000000000..4ec64e706b7021 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include +#include +#include +#include +#include +#include "MinSequenceContainer.h" +#include "min_allocator.h" + +template +void test() { + { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + + static_assert(std::same_as, typename C::iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(std::ranges::viewable_range); + + static_assert(std::same_as, typename C::const_iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(!std::ranges::viewable_range); + } +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp new file mode 100644 index 00000000000000..a16383cdcf5383 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// reverse_iterator rbegin() noexcept; +// const_reverse_iterator rbegin() const noexcept; +// reverse_iterator rend() noexcept; +// const_reverse_iterator rend() const noexcept; +// +// const_reverse_iterator crbegin() const noexcept; +// const_reverse_iterator crend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include + +#include "test_macros.h" +#include + +int main(int, char**) { + { + using M = std::flat_set, std::deque>; + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.rbegin()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.rend()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crend()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rend()), M::const_reverse_iterator); + static_assert(noexcept(m.rbegin())); + static_assert(noexcept(cm.rbegin())); + static_assert(noexcept(m.crbegin())); + static_assert(noexcept(m.rend())); + static_assert(noexcept(cm.rend())); + static_assert(noexcept(m.crend())); + assert(m.size() == 4); + assert(std::distance(m.rbegin(), m.rend()) == 4); + assert(std::distance(cm.rbegin(), cm.rend()) == 4); + assert(std::distance(m.crbegin(), m.crend()) == 4); + assert(std::distance(cm.crbegin(), cm.crend()) == 4); + M::reverse_iterator i; // default-construct + ASSERT_SAME_TYPE(decltype(*i), const int&); + i = m.rbegin(); // move-assignment + M::const_reverse_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 4; j >= 1; --j, ++i) { // pre-increment + assert(*i == j); + } + assert(i == m.rend()); + for (int j = 1; j <= 4; ++j) { + --i; // pre-decrement + assert(*i == j); + } + assert(i == m.rbegin()); + } + { + // N3644 testing + using C = std::flat_set; + C::reverse_iterator ii1{}, ii2{}; + C::reverse_iterator ii4 = ii1; + C::const_reverse_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp new file mode 100644 index 00000000000000..221a13fa057577 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// void clear() noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// test noexcept + +template +concept NoExceptClear = requires(T t) { + { t.clear() } noexcept; +}; + +static_assert(NoExceptClear>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptClear, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4, 5}; + assert(m.size() == 5); + ASSERT_NOEXCEPT(m.clear()); + ASSERT_SAME_TYPE(decltype(m.clear()), void); + m.clear(); + assert(m.size() == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp new file mode 100644 index 00000000000000..95f7a3c5f5d34a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -0,0 +1,141 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// pair emplace(Args&&... args); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the begin + M m = {3, 5, 6, 7}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted in the middle + M m = {0, 1, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the end + M m = {0, 1}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } + { + // key already exists and original at the begin + M m = {2, 3, 5, 6}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original in the middle + M m = {0, 2, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 1); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original at the end + M m = {0, 1, 2}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace()), R); + R r = m.emplace(2, 0.0); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace(1, 3.5); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace(1, 3.5); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp new file mode 100644 index 00000000000000..de855d5e5c3009 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// iterator emplace_hint(const_iterator position, Args&&... args); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace_hint(m.end(), typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + } + { + // hints correct at the begin + M m = {3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints correct at the end + M m = {0, 1}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct but key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the begin + M m = {1, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrectly in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 1; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the end + M m = {0, 3}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrect and key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace_hint(m.cbegin())), R); + R r = m.emplace_hint(m.end(), 2, 0.0); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp new file mode 100644 index 00000000000000..386af04d26e9a2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(iterator position); +// iterator erase(const_iterator position); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(std::next(m.cbegin(), 3)); + assert(m.size() == 7); + assert(i1 == std::next(m.begin(), 3)); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 5); + assert(*std::next(m.begin(), 4) == 6); + assert(*std::next(m.begin(), 5) == 7); + assert(*std::next(m.begin(), 6) == 8); + + std::same_as decltype(auto) i2 = m.erase(std::next(m.begin(), 0)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 5)); + assert(m.size() == 5); + assert(i3 == m.end()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + + std::same_as decltype(auto) i4 = m.erase(std::next(m.begin(), 1)); + assert(m.size() == 4); + assert(i4 == std::next(m.begin())); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 6); + assert(*std::next(m.begin(), 3) == 7); + + std::same_as decltype(auto) i5 = m.erase(std::next(m.cbegin(), 2)); + assert(m.size() == 3); + assert(i5 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 7); + + std::same_as decltype(auto) i6 = m.erase(std::next(m.begin(), 2)); + assert(m.size() == 2); + assert(i6 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + + std::same_as decltype(auto) i7 = m.erase(std::next(m.cbegin(), 0)); + assert(m.size() == 1); + assert(i7 == std::next(m.begin(), 0)); + assert(*m.begin() == 5); + + std::same_as decltype(auto) i8 = m.erase(m.begin()); + assert(m.size() == 0); + assert(i8 == m.begin()); + assert(i8 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp new file mode 100644 index 00000000000000..7416977844e5df --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(const_iterator first, const_iterator last); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(m.cbegin(), m.cbegin()); + assert(m.size() == 8); + assert(i1 == m.begin()); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 4); + assert(*std::next(m.begin(), 4) == 5); + assert(*std::next(m.begin(), 5) == 6); + assert(*std::next(m.begin(), 6) == 7); + assert(*std::next(m.begin(), 7) == 8); + + std::same_as decltype(auto) i2 = m.erase(m.cbegin(), std::next(m.cbegin(), 2)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 2), std::next(m.cbegin(), 6)); + assert(m.size() == 2); + assert(i3 == std::next(m.begin(), 2)); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + + std::same_as decltype(auto) i4 = m.erase(m.cbegin(), m.cend()); + assert(m.size() == 0); + assert(i4 == m.begin()); + assert(i4 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp new file mode 100644 index 00000000000000..25d4f4af19608b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(const key_type& k); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template > +void test() { + using M = std::flat_set; + + auto make = [](std::initializer_list il) { + M m; + for (int i : il) { + m.emplace(i); + } + return m; + }; + M m = make({1, 2, 3, 4, 5, 6, 7, 8}); + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(9); + assert(n == 0); + assert(m == make({1, 2, 3, 4, 5, 6, 7, 8})); + n = m.erase(4); + assert(n == 1); + assert(m == make({1, 2, 3, 5, 6, 7, 8})); + n = m.erase(1); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7, 8})); + n = m.erase(8); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7})); + n = m.erase(3); + assert(n == 1); + assert(m == make({2, 5, 6, 7})); + n = m.erase(4); + assert(n == 0); + assert(m == make({2, 5, 6, 7})); + n = m.erase(6); + assert(n == 1); + assert(m == make({2, 5, 7})); + n = m.erase(7); + assert(n == 1); + assert(m == make({2, 5})); + n = m.erase(2); + assert(n == 1); + assert(m == make({5})); + n = m.erase(5); + assert(n == 1); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test, std::greater<>>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp new file mode 100644 index 00000000000000..cbf7cac603806d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(K&& k); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanErase = requires(M m, Transparent k) { m.erase(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanErase); +static_assert(!CanErase); +static_assert(!CanErase); +static_assert(!CanErase); + +template +struct HeterogeneousKey { + explicit HeterogeneousKey(Key key, It it) : key_(key), it_(it) {} + operator It() && { return it_; } + auto operator<=>(Key key) const { return key_ <=> key; } + friend bool operator<(const HeterogeneousKey&, const HeterogeneousKey&) { + assert(false); + return false; + } + Key key_; + It it_; +}; + +template +void test_simple() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(3); // erase(K&&) [with K=int] + assert(n == 1); + assert((m == M{1, 2, 4})); + typename M::key_type lvalue = 2; + n = m.erase(lvalue); // erase(K&&) [with K=int&] + assert(n == 1); + assert((m == M{1, 4})); + const typename M::key_type const_lvalue = 1; + n = m.erase(const_lvalue); // erase(const key_type&) + assert(n == 1); + assert((m == M{4})); +} + +template +void test_transparent_comparator() { + using M = std::flat_set; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.erase(Transparent{"abc"})), typename M::size_type); + + auto n = m.erase(Transparent{"epsilon"}); + assert(n == 1); + + M expected = {"alpha", "beta", "eta", "gamma"}; + assert(m == expected); + + auto n2 = m.erase(Transparent{"aaa"}); + assert(n2 == 0); + assert(m == expected); +} + +int main(int, char**) { + test_simple>(); + test_simple>(); + test_simple>(); + test_simple>>(); + + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>>(); + + { + // P2077's HeterogeneousKey example + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.erase(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp new file mode 100644 index 00000000000000..c3bbffabb90a08 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// containers extract() &&; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanExtract = requires(T&& t) { std::forward(t).extract(); }; + +static_assert(CanExtract&&>); +static_assert(!CanExtract&>); +static_assert(!CanExtract const&>); +static_assert(!CanExtract const&&>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + M m = M({1, 2, 3}); + + std::same_as auto keys = std::move(m).extract(); + + auto expected_keys = {1, 2, 3}; + assert(std::ranges::equal(keys, expected_keys)); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // extracted object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m = M({1, 2, 3}); + std::same_as auto keys = std::move(m).extract(); + assert(keys.size() == 3); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); + } + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + auto c = std::move(m).extract(); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we try to erase the key after value emplacement failure. + // and after erasure failure, we clear the flat_set + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp new file mode 100644 index 00000000000000..c0ddadc3006987 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair insert(const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using VT = typename M::value_type; + M m; + + const VT v1(2); + std::same_as decltype(auto) r = m.insert(v1); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + + const VT v2(1); + r = m.insert(v2); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == 1); + + const VT v3(3); + r = m.insert(v3); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); + + const VT v4(3); + r = m.insert(v4); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp new file mode 100644 index 00000000000000..7381514a70eabb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; + + M m = {1,1,1,3,3,3}; + m.insert({ + 4, + 4, + 4, + 1, + 1, + 1, + 2, + 2, + 2, + }); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(*m.begin() == V(1)); + assert(*std::next(m.begin()) == V(2)); + assert(*std::next(m.begin(), 2) == V(3)); + assert(*std::next(m.begin(), 3) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp new file mode 100644 index 00000000000000..c343d53a62215a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator insert(const_iterator position, const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = typename M::iterator; + using VT = typename M::value_type; + + M m; + const VT v1(2); + std::same_as decltype(auto) r = m.insert(m.end(), v1); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + + const VT v2(1); + r = m.insert(m.end(), v2); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == 1); + + const VT v3(3); + r = m.insert(m.end(), v3); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); + + const VT v4(3); + r = m.insert(m.end(), v4); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp new file mode 100644 index 00000000000000..d20a8ef8fdd92d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + + int ar1[] = { + 2, + 2, + 2, + 1, + 1, + 1, + 3, + 3, + 3, + }; + int ar2[] = { + 4, + 4, + 4, + 1, + 1, + 1, + 0, + 0, + 0, + }; + + M m; + m.insert(cpp17_input_iterator(ar1), cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(cpp17_input_iterator(ar2), cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp new file mode 100644 index 00000000000000..84b6c7fc1d34f6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// +// iterator insert(const_iterator position, value_type&&); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "../helpers.h" +#include "test_macros.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + using R = typename M::iterator; + M m; + std::same_as decltype(auto) r = m.insert(m.end(), V(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == V(2)); + + r = m.insert(m.end(), V(1)); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == V(1)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp new file mode 100644 index 00000000000000..536307252c6405 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// void insert_range(R&& rg); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "MoveOnly.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint container-compatible-range +template +concept CanInsertRange = requires(M m, R&& r) { m.insert_range(std::forward(r)); }; + +using Set = std::flat_set; + +static_assert(CanInsertRange>); +static_assert(CanInsertRange>); +static_assert(!CanInsertRange*>>); +static_assert(!CanInsertRange*>>); + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using M = std::flat_set, KeyContainer>; + using It = forward_iterator; + M m = {10, 8, 5, 2, 1}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), It(ar + 6)}; + static_assert(std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9, 10})); + } + { + using M = std::flat_set, KeyContainer>; + using It = cpp20_input_iterator; + M m = {8, 5, 3, 2}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), sentinel_wrapper(It(ar + 6))}; + static_assert(!std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9})); + } + { + // The "uniquing" part uses the comparator, not operator==. + struct ModTen { + bool operator()(int a, int b) const { return (a % 10) < (b % 10); } + }; + using M = std::flat_set; + M m = {21, 43, 15, 37}; + int ar[] = {33, 18, 55, 18, 42}; + m.insert_range(ar); + assert((m == M{21, 42, 43, 15, 37, 18})); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // Items are forwarded correctly from the input range (P2767). + MoveOnly a[] = {3, 1, 4, 1, 5}; + std::flat_set m; + m.insert_range(a | std::views::as_rvalue); + MoveOnly expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + // The element type of the range doesn't need to be std::pair (P2767). + int pa[] = {3, 1, 4, 1, 5}; + std::deque> a(pa, pa + 5); + std::flat_set m; + m.insert_range(a); + int expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp new file mode 100644 index 00000000000000..7d95f0521eb1f6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// pair insert( value_type&& v); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + using R = std::pair; + using V = typename M::value_type; + + M m; + std::same_as decltype(auto) r = m.insert(V(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == V(2)); + + r = m.insert(V(1)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == V(1)); + + r = m.insert(V(3)); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); + + r = m.insert(V(3)); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp new file mode 100644 index 00000000000000..fa5bf86830daec --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(sorted_unique_t, initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + M m = {1, 1, 1, 3, 3, 3}; + m.insert(std::sorted_unique, {0, 1, 2, 4}); + assert(m.size() == 5); + assert(std::distance(m.begin(), m.end()) == 5); + assert(*m.begin() == V(0)); + assert(*std::next(m.begin()) == V(1)); + assert(*std::next(m.begin(), 2) == V(2)); + assert(*std::next(m.begin(), 3) == V(3)); + assert(*std::next(m.begin(), 4) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp new file mode 100644 index 00000000000000..ef7b8391cee33c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(sorted_unique_t, InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + int ar1[] = {1, 2, 3}; + + int ar2[] = {0, 2, 4}; + + M m; + m.insert(std::sorted_unique, + cpp17_input_iterator(ar1), + cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(std::sorted_unique, + cpp17_input_iterator(ar2), + cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp new file mode 100644 index 00000000000000..72d7261a182547 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -0,0 +1,169 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair insert(P&& x); +// template iterator insert(const_iterator hint, P&& x); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// Constraints: is_constructible_v is true. +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; +using Iter = Set::const_iterator; + +static_assert(CanInsert); +static_assert(CanInsert); +static_assert(!CanInsert); +static_assert(!CanInsert); + +static int expensive_comparisons = 0; +static int cheap_comparisons = 0; + +struct CompareCounter { + int i_ = 0; + CompareCounter(int i) : i_(i) {} + friend auto operator<=>(const CompareCounter& x, const CompareCounter& y) { + expensive_comparisons += 1; + return x.i_ <=> y.i_; + } + bool operator==(const CompareCounter&) const = default; + friend auto operator<=>(const CompareCounter& x, int y) { + cheap_comparisons += 1; + return x.i_ <=> y; + } +}; + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + const int expected[] = {1, 2, 3, 4, 5}; + { + // insert(P&&) + // Unlike flat_set, here we can't use key_compare to compare value_type versus P, + // so we must eagerly convert to value_type. + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, P&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // insert(value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens last + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // emplace(Args&&...) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.emplace(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // no ambiguity between insert(pos, P&&) and insert(first, last) + using M = std::flat_set; + struct Evil { + operator M::value_type() const; + operator M::const_iterator() const; + }; + std::flat_set m; + ASSERT_SAME_TYPE(decltype(m.insert(Evil())), std::pair); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); + } + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(t); + }; + test_emplace_exception_guarantee(insert_func); + } + { + auto insert_func_iter = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(m.begin(), t); + }; + test_emplace_exception_guarantee(insert_func_iter); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp new file mode 100644 index 00000000000000..49cb6eb6163c90 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void replace(container_type&& key_cont); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanReplace = requires(T t, Args&&... args) { t.replace(std::forward(args)...); }; + +using Set = std::flat_set; +static_assert(CanReplace>); +static_assert(!CanReplace&>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = M({1, 2, 3}); + KeyContainer new_keys = {7, 8}; + auto expected_keys = new_keys; + m.replace(std::move(new_keys)); + assert(m.size() == 2); + assert(std::ranges::equal(m, expected_keys)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp new file mode 100644 index 00000000000000..23a2dc85989bb7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// `check_assertion.h` requires Unix headers and regex support. +// REQUIRES: has-unix-headers +// UNSUPPORTED: no-localization +// UNSUPPORTED: no-exceptions + +// + +// void swap(flat_set& y) noexcept; +// friend void swap(flat_set& x, flat_set& y) noexcept + +// Test that std::terminate is called if any exception is thrown during swap + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../helpers.h" +#include "check_assertion.h" + +template +void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) { + { + // key swap throws + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m1, m2; + m1.emplace(1); + m1.emplace(2); + m2.emplace(3); + m2.emplace(4); + // swap is noexcept + EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); }); + } +} + +int main(int, char**) { + { + auto swap_func = [](auto& m1, auto& m2) { swap(m1, m2); }; + test_swap_exception_guarantee(swap_func); + } + + { + auto swap_func = [](auto& m1, auto& m2) { m1.swap(m2); }; + test_swap_exception_guarantee(swap_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp new file mode 100644 index 00000000000000..bc7baa67e52a59 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend void swap(flat_set& x, flat_set& y) noexcept + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptAdlSwap = requires(T t1, T t2) { + { swap(t1, t2) } noexcept; +}; + +static_assert(NoExceptAdlSwap>); + +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptAdlSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp new file mode 100644 index 00000000000000..b0b06a9499efc7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void swap(flat_set& y) noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptMemberSwap = requires(T t1, T t2) { + { t1.swap(t2) } noexcept; +}; + +static_assert(NoExceptMemberSwap>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptMemberSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp new file mode 100644 index 00000000000000..971b5e1c338dd1 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// key_compare key_comp() const; +// value_compare value_comp() const; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + { + using M = std::flat_set; + using Comp = std::less; // the default + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + { + using Comp = std::function; + using M = std::flat_set; + Comp comp = std::greater(); + M m({}, comp); + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(!kc(1, 2)); + assert(kc(2, 1)); + auto vc = m.value_comp(); + assert(!vc(1, 2)); + assert(vc(2, 1)); + } + { + using Comp = std::less<>; + using M = std::flat_set; + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + auto a = std::make_pair(1, 2); + ASSERT_SAME_TYPE(decltype(vc(a, a)), bool); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp new file mode 100644 index 00000000000000..b14da66f611301 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// bool contains(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp new file mode 100644 index 00000000000000..507560608952b0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template bool contains(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanContains = requires(M m, Transparent k) { m.contains(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanContains); +static_assert(CanContains); +static_assert(!CanContains); +static_assert(!CanContains); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.contains(Transparent{"abc"})), bool); + ASSERT_SAME_TYPE(decltype(std::as_const(m).contains(Transparent{"b"})), bool); + assert(m.contains(Transparent{"alpha"}) == true); + assert(m.contains(Transparent{"beta"}) == true); + assert(m.contains(Transparent{"epsilon"}) == true); + assert(m.contains(Transparent{"eta"}) == true); + assert(m.contains(Transparent{"gamma"}) == true); + assert(m.contains(Transparent{"al"}) == false); + assert(m.contains(Transparent{""}) == false); + assert(m.contains(Transparent{"g"}) == false); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto b = m.contains(Transparent{3}); + assert(b); + assert(transparent_used); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp new file mode 100644 index 00000000000000..478f615358b606 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type count(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using S = typename KeyContainer::size_type; + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp new file mode 100644 index 00000000000000..b591258f74399c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template size_type count(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanCount = requires(M m, Transparent k) { m.count(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanCount); +static_assert(CanCount); +static_assert(!CanCount); +static_assert(!CanCount); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.count(Transparent{"abc"})), typename M::size_type); + ASSERT_SAME_TYPE(decltype(std::as_const(m).count(Transparent{"b"})), typename M::size_type); + assert(m.count(Transparent{"alpha"}) == 1); + assert(m.count(Transparent{"beta"}) == 1); + assert(m.count(Transparent{"epsilon"}) == 1); + assert(m.count(Transparent{"eta"}) == 1); + assert(m.count(Transparent{"gamma"}) == 1); + assert(m.count(Transparent{"al"}) == 0); + assert(m.count(Transparent{""}) == 0); + assert(m.count(Transparent{"g"}) == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.count(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp new file mode 100644 index 00000000000000..a088b7fee17d2c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair equal_range(const key_type& k); +// pair equal_range(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin, begin)); + assert(m.equal_range(1) == std::pair(begin, begin + 1)); + assert(m.equal_range(2) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(3) == std::pair(begin + 2, begin + 2)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(6) == std::pair(begin + 4, begin + 4)); + assert(m.equal_range(7) == std::pair(begin + 4, begin + 4)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin() + 4, m.cbegin() + 5)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin() + 5, m.cbegin() + 5)); + } + + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin + 5, begin + 5)); + assert(m.equal_range(1) == std::pair(begin + 4, begin + 5)); + assert(m.equal_range(2) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(3) == std::pair(begin + 3, begin + 3)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(6) == std::pair(begin + 1, begin + 1)); + assert(m.equal_range(7) == std::pair(begin + 1, begin + 1)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin(), m.cbegin() + 1)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin(), m.cbegin())); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp new file mode 100644 index 00000000000000..ede5d91e19b9fd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair equal_range(const K& x); +// template pair equal_range(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanEqualRange = requires(M m, Transparent k) { m.equal_range(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanEqualRange); +static_assert(CanEqualRange); +static_assert(!CanEqualRange); +static_assert(!CanEqualRange); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + using R = std::pair; + using CR = std::pair; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.equal_range(Transparent{"abc"})), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(Transparent{"b"})), CR); + + auto test_found = [&](auto&& map, const std::string& expected_key) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(last - first == 1); + assert(*first == expected_key); + }; + + auto test_not_found = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(first == last); + assert(first - m.begin() == expected_offset); + }; + + test_found(m, "alpha"); + test_found(m, "beta"); + test_found(m, "epsilon"); + test_found(m, "eta"); + test_found(m, "gamma"); + test_found(cm, "alpha"); + test_found(cm, "beta"); + test_found(cm, "epsilon"); + test_found(cm, "eta"); + test_found(cm, "gamma"); + + test_not_found(m, "charlie", 2); + test_not_found(m, "aaa", 0); + test_not_found(m, "zzz", 5); + test_not_found(cm, "charlie", 2); + test_not_found(cm, "aaa", 0); + test_not_found(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto p = m.equal_range(Transparent{3}); + assert(p.first != p.second); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp new file mode 100644 index 00000000000000..cf0dd2d1dd831c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator find(const key_type& k); +// const_iterator find(const key_type& k) const; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.find(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(0)), typename M::const_iterator); + assert(m.find(0) == m.end()); + assert(m.find(1) == m.begin()); + assert(m.find(2) == m.begin() + 1); + assert(m.find(3) == m.end()); + assert(m.find(4) == m.begin() + 2); + assert(m.find(5) == m.begin() + 3); + assert(m.find(6) == m.end()); + assert(m.find(7) == m.end()); + assert(std::as_const(m).find(8) == m.begin() + 4); + assert(std::as_const(m).find(9) == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp new file mode 100644 index 00000000000000..730a57b0a6cb85 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator find(const K& x); +// template const_iterator find(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanFind = requires(M m, Transparent k) { m.find(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanFind); +static_assert(CanFind); +static_assert(!CanFind); +static_assert(!CanFind); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.find(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(Transparent{"b"})), typename M::const_iterator); + + auto test_find = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.find(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_find(m, "alpha", 0); + test_find(m, "beta", 1); + test_find(m, "epsilon", 2); + test_find(m, "eta", 3); + test_find(m, "gamma", 4); + test_find(m, "charlie", 5); + test_find(m, "aaa", 5); + test_find(m, "zzz", 5); + test_find(cm, "alpha", 0); + test_find(cm, "beta", 1); + test_find(cm, "epsilon", 2); + test_find(cm, "eta", 3); + test_find(cm, "gamma", 4); + test_find(cm, "charlie", 5); + test_find(cm, "aaa", 5); + test_find(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.find(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp new file mode 100644 index 00000000000000..093c32e537ed35 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator lower_bound(const key_type& k); +// const_iterator lower_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.begin()); + assert(m.lower_bound(1) == m.begin()); + assert(m.lower_bound(2) == m.begin() + 1); + assert(m.lower_bound(3) == m.begin() + 2); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 3); + assert(m.lower_bound(6) == m.begin() + 4); + assert(m.lower_bound(7) == m.begin() + 4); + assert(std::as_const(m).lower_bound(8) == m.begin() + 4); + assert(std::as_const(m).lower_bound(9) == m.end()); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.end()); + assert(m.lower_bound(1) == m.begin() + 4); + assert(m.lower_bound(2) == m.begin() + 3); + assert(m.lower_bound(3) == m.begin() + 3); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 1); + assert(m.lower_bound(6) == m.begin() + 1); + assert(m.lower_bound(7) == m.begin() + 1); + assert(std::as_const(m).lower_bound(8) == m.begin()); + assert(std::as_const(m).lower_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp new file mode 100644 index 00000000000000..18f9bc6dd32955 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator lower_bound(const K& x); +// template const_iterator lower_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanLowerBound = requires(M m, Transparent k) { m.lower_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanLowerBound); +static_assert(CanLowerBound); +static_assert(!CanLowerBound); +static_assert(!CanLowerBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_lower_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.lower_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_lower_bound(m, "abc", 0); + test_lower_bound(m, "alpha", 0); + test_lower_bound(m, "beta", 1); + test_lower_bound(m, "bets", 2); + test_lower_bound(m, "charlie", 2); + test_lower_bound(m, "echo", 2); + test_lower_bound(m, "epsilon", 2); + test_lower_bound(m, "eta", 3); + test_lower_bound(m, "gamma", 4); + test_lower_bound(m, "golf", 5); + test_lower_bound(m, "zzz", 5); + + test_lower_bound(cm, "abc", 0); + test_lower_bound(cm, "alpha", 0); + test_lower_bound(cm, "beta", 1); + test_lower_bound(cm, "bets", 2); + test_lower_bound(cm, "charlie", 2); + test_lower_bound(cm, "echo", 2); + test_lower_bound(cm, "epsilon", 2); + test_lower_bound(cm, "eta", 3); + test_lower_bound(cm, "gamma", 4); + test_lower_bound(cm, "golf", 5); + test_lower_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.lower_bound(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp new file mode 100644 index 00000000000000..ab34de85103175 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator upper_bound(const key_type& k); +// const_iterator upper_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.begin()); + assert(m.upper_bound(1) == m.begin() + 1); + assert(m.upper_bound(2) == m.begin() + 2); + assert(m.upper_bound(3) == m.begin() + 2); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 4); + assert(m.upper_bound(6) == m.begin() + 4); + assert(std::as_const(m).upper_bound(7) == m.begin() + 4); + assert(std::as_const(m).upper_bound(8) == m.end()); + assert(std::as_const(m).upper_bound(9) == m.end()); + } + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.end()); + assert(m.upper_bound(1) == m.end()); + assert(m.upper_bound(2) == m.begin() + 4); + assert(m.upper_bound(3) == m.begin() + 3); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 2); + assert(m.upper_bound(6) == m.begin() + 1); + assert(m.upper_bound(7) == m.begin() + 1); + assert(std::as_const(m).upper_bound(8) == m.begin() + 1); + assert(std::as_const(m).upper_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp new file mode 100644 index 00000000000000..69ce2ae926a305 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator upper_bound(const K& x); +// template const_iterator upper_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanUpperBound = requires(M m, Transparent k) { m.upper_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanUpperBound); +static_assert(CanUpperBound); +static_assert(!CanUpperBound); +static_assert(!CanUpperBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_upper_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.upper_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_upper_bound(m, "abc", 0); + test_upper_bound(m, "alpha", 1); + test_upper_bound(m, "beta", 2); + test_upper_bound(m, "bets", 2); + test_upper_bound(m, "charlie", 2); + test_upper_bound(m, "echo", 2); + test_upper_bound(m, "epsilon", 3); + test_upper_bound(m, "eta", 4); + test_upper_bound(m, "gamma", 5); + test_upper_bound(m, "golf", 5); + test_upper_bound(m, "zzz", 5); + + test_upper_bound(cm, "abc", 0); + test_upper_bound(cm, "alpha", 1); + test_upper_bound(cm, "beta", 2); + test_upper_bound(cm, "bets", 2); + test_upper_bound(cm, "charlie", 2); + test_upper_bound(cm, "echo", 2); + test_upper_bound(cm, "epsilon", 3); + test_upper_bound(cm, "eta", 4); + test_upper_bound(cm, "gamma", 5); + test_upper_bound(cm, "golf", 5); + test_upper_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.upper_bound(Transparent{2}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h new file mode 100644 index 00000000000000..9fff262d84234e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -0,0 +1,294 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_flat_set_HELPERS_H +#define SUPPORT_flat_set_HELPERS_H + +#include +#include +#include +#include +#include + +#include "test_allocator.h" +#include "test_macros.h" + +template +void check_invariant(const std::flat_set& m) { + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); + auto key_equal = [&](const auto& x, const auto& y) { + const auto& c = m.key_comp(); + return !c(x, y) && !c(y, x); + }; + assert(std::adjacent_find(m.begin(), m.end(), key_equal) == m.end()); +} + +struct StartsWith { + explicit StartsWith(char ch) : lower_(1, ch), upper_(1, ch + 1) {} + StartsWith(const StartsWith&) = delete; + void operator=(const StartsWith&) = delete; + struct Less { + using is_transparent = void; + bool operator()(const std::string& a, const std::string& b) const { return a < b; } + bool operator()(const StartsWith& a, const std::string& b) const { return a.upper_ <= b; } + bool operator()(const std::string& a, const StartsWith& b) const { return a < b.lower_; } + bool operator()(const StartsWith&, const StartsWith&) const { + assert(false); // should not be called + return false; + } + }; + +private: + std::string lower_; + std::string upper_; +}; + +template +struct CopyOnlyVector : std::vector { + using std::vector::vector; + + CopyOnlyVector(const CopyOnlyVector&) = default; + CopyOnlyVector(CopyOnlyVector&& other) : CopyOnlyVector(other) {} + CopyOnlyVector(CopyOnlyVector&& other, std::vector::allocator_type alloc) : CopyOnlyVector(other, alloc) {} + + CopyOnlyVector& operator=(const CopyOnlyVector&) = default; + CopyOnlyVector& operator=(CopyOnlyVector& other) { return this->operator=(other); } +}; + +template +struct Transparent { + T t; + + operator T() const + requires ConvertibleToT + { + return t; + } +}; + +template +using ConvertibleTransparent = Transparent; + +template +using NonConvertibleTransparent = Transparent; + +struct TransparentComparator { + using is_transparent = void; + + bool* transparent_used = nullptr; + TransparentComparator() = default; + TransparentComparator(bool& used) : transparent_used(&used) {} + + template + bool operator()(const T& t, const Transparent& transparent) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return t < transparent.t; + } + + template + bool operator()(const Transparent& transparent, const T& t) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return transparent.t < t; + } + + template + bool operator()(const T& t1, const T& t2) const { + return t1 < t2; + } +}; + +struct NonTransparentComparator { + template + bool operator()(const T&, const Transparent&) const; + + template + bool operator()(const Transparent&, const T&) const; + + template + bool operator()(const T&, const T&) const; +}; + +struct NoDefaultCtr { + NoDefaultCtr() = delete; +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +struct EmplaceUnsafeContainer : std::vector { + using std::vector::vector; + + template + auto emplace(Args&&... args) -> decltype(std::declval>().emplace(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } + + template + auto insert(Args&&... args) -> decltype(std::declval>().insert(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } +}; + +template +struct ThrowOnEraseContainer : std::vector { + using std::vector::vector; + + template + auto erase(Args&&... args) -> decltype(std::declval>().erase(std::forward(args)...)) { + throw 42; + } +}; + +template +struct ThrowOnMoveContainer : std::vector { + using std::vector::vector; + + ThrowOnMoveContainer(ThrowOnMoveContainer&&) { throw 42; } + + ThrowOnMoveContainer& operator=(ThrowOnMoveContainer&&) { throw 42; } +}; + +#endif + +template +void test_emplace_exception_guarantee([[maybe_unused]] F&& emplace_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using C = TransparentComparator; + { + // Throw on emplace the key, and underlying has strong exception guarantee + using KeyContainer = std::vector>; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + + test_allocator_statistics stats; + + KeyContainer a({1, 2, 3, 4}, test_allocator{&stats}); + [[maybe_unused]] auto expected_keys = a; + M m(std::sorted_unique, std::move(a)); + + stats.throw_after = 1; + try { + emplace_function(m, 0); + assert(false); + } catch (const std::bad_alloc&) { + check_invariant(m); + // In libc++, the flat_set is unchanged + LIBCPP_ASSERT(m.size() == 4); + LIBCPP_ASSERT(std::ranges::equal(m, expected_keys)); + } + } + { + // Throw on emplace the key, and underlying has no strong exception guarantee + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(!std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + KeyContainer a = {1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + emplace_function(m, 0); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, the flat_set is cleared + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} + +template +void test_insert_range_exception_guarantee([[maybe_unused]] F&& insert_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + test_allocator_statistics stats; + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + + std::vector newValues = {0, 1, 5, 6, 7, 8}; + stats.throw_after = 1; + try { + insert_function(m, newValues); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when inserting a range + LIBCPP_ASSERT(m.size() == 0); + } +#endif +} + +template +void test_erase_exception_guarantee([[maybe_unused]] F&& erase_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + { + // key erase throws + using KeyContainer = ThrowOnEraseContainer; + using M = std::flat_set; + + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + erase_function(m, 3); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when erasing + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} +class Moveable { + int int_; + double double_; + +public: + Moveable() : int_(0), double_(0) {} + Moveable(int i, double d) : int_(i), double_(d) {} + Moveable(Moveable&& x) : int_(x.int_), double_(x.double_) { + x.int_ = -1; + x.double_ = -1; + } + Moveable& operator=(Moveable&& x) { + int_ = x.int_; + x.int_ = -1; + double_ = x.double_; + x.double_ = -1; + return *this; + } + + Moveable(const Moveable&) = delete; + Moveable& operator=(const Moveable&) = delete; + bool operator==(const Moveable& x) const { return int_ == x.int_ && double_ == x.double_; } + bool operator<(const Moveable& x) const { return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_); } + + int get() const { return int_; } + bool moved() const { return int_ == -1; } +}; + +#endif // SUPPORT_flat_set_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp new file mode 100644 index 00000000000000..c4a9810016536b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Check that std::flat_set and its iterators can be instantiated with an incomplete +// type. + +#include +#include + +struct A { + using Set = std::flat_set
; + int data; + Set m; + Set::iterator it; + Set::const_iterator cit; +}; + +// Implement the operator< required in order to instantiate flat_set +bool operator<(A const& L, A const& R) { return L.data < R.data; } + +int main(int, char**) { + A a; + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp new file mode 100644 index 00000000000000..f6d08bb736d300 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend bool operator==(const flat_set& x, const flat_set& y); +// friend synth-three-way-result +// operator<=>(const flat_set& x, const flat_set& y); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_comparisons.h" +#include "test_container_comparisons.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, true)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } + { + // Comparisons use value_type's native operators, not the comparator + using C = std::flat_set>; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, false)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = C(std::sorted_unique, {std::numeric_limits::quiet_NaN()}); + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + } + { + // Comparisons use value_type's native operators, not the comparator + struct StrongComp { + bool operator()(double a, double b) const { return std::strong_order(a, b) < 0; } + }; + using C = std::flat_set; + C s1 = {1}; + C s2 = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + s1 = {1, std::numeric_limits::quiet_NaN(), 1}; + s2 = {std::numeric_limits::quiet_NaN(), 1}; + assert(std::lexicographical_compare_three_way(s1.begin(), s1.end(), s2.begin(), s2.end(), std::strong_order) == + std::strong_ordering::equal); + assert(s1 != s2); + assert((s1 <=> s2) == std::partial_ordering::unordered); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp new file mode 100644 index 00000000000000..a845b2b81e89d3 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// using key_type = Key; +// using value_type = Key; +// using key_compare = Compare; +// using value_compare = Compare; +// using reference = value_type&; +// using const_reference = const value_type&; +// using size_type = typename KeyContainer::size_type; +// using difference_type = typename KeyContainer::difference_type; +// using iterator = implementation-defined; // see [container.requirements] +// using const_iterator = implementation-defined; // see [container.requirements] +// using reverse_iterator = std::reverse_iterator; +// using const_reverse_iterator = std::reverse_iterator; +// using container_type = KeyContainer; + +#include +#include +#include +#include +#include +#include +#include +#include "min_allocator.h" + +void test() { + { + using M = std::flat_set; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(requires { typename M::value_compare; }); + } + + { + struct A {}; + struct Compare { + bool operator()(const std::string&, const std::string&) const; + }; + using M = std::flat_set>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + } + { + using C = std::flat_set, std::deque>>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + // size_type is invariably size_t + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>>); + } +} >From 96903d9c8f1ea42de65fbe1a07e59413a1630d1e Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 13:21:24 +0000 Subject: [PATCH 2/6] review --- libcxx/include/__flat_set/flat_set.h | 137 +++---- .../flat.set/flat.set.capacity/empty.pass.cpp | 14 +- .../flat.set.capacity/max_size.pass.cpp | 8 +- .../flat.set/flat.set.capacity/size.pass.cpp | 14 +- .../flat.set/flat.set.cons/alloc.pass.cpp | 6 +- .../assign_initializer_list.pass.cpp | 19 +- .../flat.set/flat.set.cons/compare.pass.cpp | 6 +- .../flat.set.cons/containers.pass.cpp | 25 +- .../flat.set/flat.set.cons/copy.pass.cpp | 6 +- .../flat.set.cons/copy_alloc.pass.cpp | 6 +- .../copy_assign.addressof.compile.pass.cpp | 30 -- .../flat.set.cons/copy_assign.pass.cpp | 17 +- .../flat.set/flat.set.cons/deduct.pass.cpp | 353 +++++++++--------- .../flat.set/flat.set.cons/default.pass.cpp | 36 +- .../flat.set.cons/default_noexcept.pass.cpp | 58 --- .../flat.set.cons/dtor_noexcept.pass.cpp | 6 +- .../flat.set.cons/initializer_list.pass.cpp | 6 +- .../flat.set/flat.set.cons/iter_iter.pass.cpp | 6 +- .../flat.set/flat.set.cons/move.pass.cpp | 107 +++++- .../flat.set.cons/move_alloc.pass.cpp | 10 +- .../flat.set.cons/move_assign.pass.cpp | 141 ++++++- .../flat.set.cons/move_assign_clears.pass.cpp | 101 ----- .../move_assign_noexcept.pass.cpp | 85 ----- .../flat.set.cons/move_exceptions.pass.cpp | 58 --- .../flat.set.cons/move_noexcept.pass.cpp | 94 ----- .../flat.set/flat.set.cons/pmr.pass.cpp | 6 +- .../flat.set/flat.set.cons/range.pass.cpp | 6 +- .../flat.set.cons/sorted_container.pass.cpp | 6 +- .../sorted_initializer_list.pass.cpp | 10 +- .../flat.set.cons/sorted_iter_iter.pass.cpp | 6 +- .../flat.set.erasure/erase_if.pass.cpp | 20 +- .../erase_if_exceptions.pass.cpp | 7 +- .../flat.set.iterators/iterator.pass.cpp | 18 +- .../iterator_comparison.pass.cpp | 14 +- .../reverse_iterator.pass.cpp | 8 +- .../flat.set.modifiers/clear.pass.cpp | 18 +- .../flat.set.modifiers/emplace.pass.cpp | 25 +- .../flat.set.modifiers/emplace_hint.pass.cpp | 25 +- .../flat.set.modifiers/erase_iter.pass.cpp | 25 +- .../erase_iter_iter.pass.cpp | 24 +- .../flat.set.modifiers/erase_key.pass.cpp | 37 +- .../erase_key_transparent.pass.cpp | 34 +- .../flat.set.modifiers/extract.pass.cpp | 21 +- .../flat.set.modifiers/insert_cv.pass.cpp | 33 +- .../insert_initializer_list.pass.cpp | 42 ++- .../insert_iter_cv.pass.cpp | 23 +- .../insert_iter_iter.pass.cpp | 27 +- .../insert_iter_rv.pass.cpp | 43 ++- .../flat.set.modifiers/insert_range.pass.cpp | 38 +- .../flat.set.modifiers/insert_rv.pass.cpp | 42 ++- .../insert_sorted_initializer_list.pass.cpp | 35 +- .../insert_sorted_iter_iter.pass.cpp | 29 +- .../insert_transparent.pass.cpp | 21 +- .../flat.set.modifiers/replace.pass.cpp | 50 +-- .../flat.set.modifiers/swap_free.pass.cpp | 16 +- .../flat.set.modifiers/swap_member.pass.cpp | 14 +- .../flat.set/flat.set.observers/comp.pass.cpp | 6 +- .../flat.set.operations/contains.pass.cpp | 14 +- .../contains_transparent.pass.cpp | 17 +- .../flat.set.operations/count.pass.cpp | 14 +- .../count_transparent.pass.cpp | 16 +- .../flat.set.operations/equal_range.pass.cpp | 14 +- .../equal_range_transparent.pass.cpp | 16 +- .../flat.set.operations/find.pass.cpp | 14 +- .../find_transparent.pass.cpp | 16 +- .../flat.set.operations/lower_bound.pass.cpp | 14 +- .../lower_bound_transparent.pass.cpp | 16 +- .../flat.set.operations/upper_bound.pass.cpp | 14 +- .../upper_bound_transparent.pass.cpp | 17 +- .../container.adaptors/flat.set/helpers.h | 19 +- .../flat.set/incomplete_type.pass.cpp | 5 +- .../flat.set/op_compare.pass.cpp | 17 +- 72 files changed, 1214 insertions(+), 1087 deletions(-) delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index c920632c453bf5..37e4c9f7c686b0 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP___FLAT_set_FLAT_SET_H -#define _LIBCPP___FLAT_set_FLAT_SET_H +#ifndef _LIBCPP___FLAT_SET_FLAT_SET_H +#define _LIBCPP___FLAT_SET_FLAT_SET_H #include <__algorithm/lexicographical_compare_three_way.h> #include <__algorithm/min.h> @@ -99,13 +99,6 @@ class flat_set { using const_reverse_iterator = std::reverse_iterator; using container_type = _KeyContainer; -private: - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = - uses_allocator::value; - - _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; - public: // [flat.set.cons], construct/copy/destroy _LIBCPP_HIDE_FROM_ABI @@ -178,31 +171,31 @@ class flat_set { : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( @@ -210,7 +203,7 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { @@ -219,12 +212,12 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) # if _LIBCPP_HAS_EXCEPTIONS try @@ -239,14 +232,14 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert(__first, __last); } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { @@ -254,7 +247,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { @@ -262,7 +255,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, @@ -274,37 +267,37 @@ class flat_set { } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert_range(std::forward<_Range>(__rg)); } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { insert_range(std::forward<_Range>(__rg)); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} @@ -334,11 +327,8 @@ class flat_set { // iterators _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } @@ -382,7 +372,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { return emplace(std::forward<_Kp>(__x)); } @@ -395,7 +385,7 @@ class flat_set { } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { return emplace_hint(__hint, std::forward<_Kp>(__x)); } @@ -425,7 +415,7 @@ class flat_set { __reserve(ranges::size(__range)); } - __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + __append_sort_merge_unique(std::forward<_Range>(__range)); } _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } @@ -468,7 +458,7 @@ class flat_set { } template - requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> && !is_convertible_v<_Kp &&, const_iterator>) _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { auto [__first, __last] = equal_range(__x); @@ -505,13 +495,13 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { return __find_impl(*this, __x); } @@ -519,7 +509,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { return contains(__x) ? 1 : 0; } @@ -527,7 +517,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { return find(__x) != end(); } @@ -541,13 +531,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { return ranges::lower_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { return ranges::lower_bound(__keys_, __x, __compare_); } @@ -561,13 +551,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { return ranges::upper_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { return ranges::upper_bound(__keys_, __x, __compare_); } @@ -581,12 +571,12 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { return __equal_range_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { return __equal_range_impl(*this, __x); } @@ -611,14 +601,14 @@ class flat_set { }; template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), __compare_(std::forward<_CompArg>(__comp)...) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc)), __compare_(std::forward<_CompArg>(__comp)...) {} @@ -637,17 +627,30 @@ class flat_set { __keys_.erase(__dup_start, __keys_.end()); } - template - _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { - auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); - size_type __old_size = size(); - if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { - __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + template + _LIBCPP_HIDE_FROM_ABI void __append(_InputIterator __first, _InputIterator __last) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append(_Range&& __rng) { + if constexpr (requires { __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); }) { + // C++23 Sequence Container should have insert_range member function + __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); + } else if constexpr (ranges::common_range<_Range>) { + __keys_.insert(__keys_.end(), ranges::begin(__rng), ranges::end(__rng)); } else { - for (; __first != __last; ++__first) { - __keys_.insert(__keys_.end(), *__first); + for (auto&& __x : __rng) { + __keys_.insert(__keys_.end(), std::forward(__x)); } } + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_Args&&... __args) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + __append(std::forward<_Args>(__args)...); if (size() != __old_size) { if constexpr (!_WasSorted) { ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); @@ -831,18 +834,18 @@ template struct uses_allocator, _Allocator> : bool_constant> {}; - template - _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type - erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { - auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); - auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { - return static_cast(__pred(e)); - }); - auto __res = __flat_set.__keys_.end() - __it; - __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); - __guard.__complete(); - return __res; - } +template +_LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type +erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; +} _LIBCPP_END_NAMESPACE_STD @@ -850,4 +853,4 @@ _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS -#endif // _LIBCPP___FLAT_set_FLAT_SET_H +#endif // _LIBCPP___FLAT_SET_FLAT_SET_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp index 204df1d681af1b..223b92fc3e8e84 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m; @@ -38,11 +38,15 @@ void test() { assert(m.empty()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index cd7f424e00ece2..0489d886257911 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -24,7 +24,8 @@ #include "test_allocator.h" #include "test_macros.h" -int main(int, char**) { +void test() { + { using A1 = limited_allocator; using C = std::flat_set, std::vector>; @@ -59,5 +60,10 @@ int main(int, char**) { assert(c.max_size() <= max_dist); assert(c.max_size() <= alloc_max_size(std::allocator())); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp index 7c156e95ecb1c8..9f5ffdd0663513 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; using S = typename M::size_type; { @@ -56,11 +56,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp index acc0817d7cac4d..d14e883dd5e936 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -22,7 +22,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -55,6 +55,10 @@ int main(int, char**) { auto v = std::move(m).extract(); assert(v.get_allocator().get_id() == 5); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7f75f1e1611e3b..7e948d7c5fe976 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -33,7 +33,6 @@ void test() { m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); - LIBCPP_ASSERT(std::ranges::equal(m, expected)); } { M m = {10, 8}; @@ -44,13 +43,17 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp index b3bee18f5a936b..110757a1bb9ab6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -78,6 +78,10 @@ int main(int, char**) { auto keys = std::move(m).extract(); assert(keys.get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp index 3d1e6240c952e8..6b1246885bf527 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -36,7 +36,7 @@ void conversion_test(T); template concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -116,21 +116,16 @@ int main(int, char**) { auto m = M(ks, A(4)); // replaces the allocators assert(!ks.empty()); // it was an lvalue above assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); + auto keys = M(m).extract(); assert(keys.get_allocator() == A(4)); - } - { - // flat_set(container_type , const Allocator&) + // explicit(false) - using A = test_allocator; - using M = std::flat_set, std::deque>; static_assert(ImplicitlyConstructible&, const A&>); - auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); - M m = {ks, A(4)}; // implicit ctor - assert(!ks.empty()); // it was an lvalue above - assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); - assert(keys.get_allocator() == A(4)); + M m2 = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert(m2 == m); + auto keys2 = std::move(m).extract(); + assert(keys2.get_allocator() == A(4)); } { // flat_set(container_type , key_compare, const Allocator&) @@ -153,6 +148,10 @@ int main(int, char**) { keys = std::move(m2).extract(); assert(keys.get_allocator() == A(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp index f1dbc955e1b0de..1ba550d98f01f6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -21,7 +21,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; std::vector> ks({1, 3, 5}, test_allocator(6)); @@ -59,6 +59,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == other_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp index 59fb9d0a38366f..5011bd20030641 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -23,7 +23,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -58,6 +58,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == test_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp deleted file mode 100644 index 169b469f3bca68..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp +++ /dev/null @@ -1,30 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(const flat_set& s); - -// Validate whether the container can be copy-assigned (move-assigned, swapped) -// with an ADL-hijacking operator& - -#include -#include - -#include "test_macros.h" -#include "operator_hijacker.h" - -void test() { - std::flat_set so; - std::flat_set s; - s = so; - s = std::move(so); - swap(s, so); -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp index cdd5045f4bb9f7..695363e3aeabab 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -17,11 +17,12 @@ #include #include +#include "operator_hijacker.h" #include "test_macros.h" #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // test_allocator is not propagated using C = test_less; @@ -81,5 +82,19 @@ int main(int, char**) { m = static_cast(m); assert((m == M{{1, 2}})); } + { + // Validate whether the container can be copy-assigned (move-assigned, swapped) + // with an ADL-hijacking operator& + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); + } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp index 612e64a7c42f23..607fe0d1a9713a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -26,24 +26,21 @@ #include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" -using P = std::pair; -using PC = std::pair; - void test_copy() { { - std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set source = {1, 2}; std::flat_set s(source); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s{source}; // braces instead of parens ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s(source, std::allocator()); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); @@ -52,275 +49,259 @@ void test_copy() { void test_containers() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); - std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + int expected[] = {1, 2, 3, INT_MAX}; { - std::flat_set s(ks, vs); + std::flat_set s(ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + std::flat_set s(std::sorted_unique, sorted_ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, test_allocator(0, 44)); + std::flat_set s(ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_containers_compare() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); - std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + int expected[] = {INT_MAX, 3, 2, 1}; { - std::flat_set s(ks, vs, std::greater()); + std::flat_set s(ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_iter_iter() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const int arr[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arr[] = {1, 2, 3, INT_MAX}; + const int arrc[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arrc[] = {1, 2, 3, INT_MAX}; { std::flat_set m(std::begin(arr), std::end(arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::begin(arrc), std::end(arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.begin(), mo.end()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.cbegin(), mo.cend()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); - } - { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); + // This does not deduce to flat_set(InputIterator, InputIterator) + // But deduces to flat_set(initializer_list) + int source[3] = {1, 2, 3}; + std::flat_set s = {source, source + 3}; + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 2); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + int source[3] = {1, 2, 3}; std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); assert(s.size() == 3); } } void test_iter_iter_compare() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m(std::begin(arr), std::end(arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::begin(arrc), std::end(arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set mo; - std::flat_set m(mo.begin(), mo.end(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } - { - std::flat_set mo; - std::flat_set m(mo.cbegin(), mo.cend(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } + // const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m(std::begin(arr), std::end(arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.begin(), mo.end(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.cbegin(), mo.cend(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } } void test_initializer_list() { - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - { - std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - } - { - using M = std::flat_set; - M m; - std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - assert(s[m] == m); - } + // const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + // { + // std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // } + // { + // using M = std::flat_set; + // M m; + // std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // assert(s[m] == m); + // } } void test_initializer_list_compare() { - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } } void test_from_range() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; - { - std::flat_set s(std::from_range, r); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + // { + // std::flat_set s(std::from_range, r); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } void test_from_range_compare() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; - { - std::flat_set s(std::from_range, r, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + // { + // std::flat_set s(std::from_range, r, std::greater()); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } int main(int, char**) { @@ -335,7 +316,7 @@ int main(int, char**) { test_from_range(); test_from_range_compare(); - AssociativeContainerDeductionGuidesSfinaeAway>(); + AssociativeContainerDeductionGuidesSfinaeAway>(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp index 64b0bfcb383a72..292af96c61582f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -19,9 +19,10 @@ #include #include -#include "test_macros.h" #include "min_allocator.h" +#include "MoveOnly.h" #include "test_allocator.h" +#include "test_macros.h" struct DefaultCtableComp { explicit DefaultCtableComp() { default_constructed_ = true; } @@ -29,7 +30,12 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +void test() { { std::flat_set m; assert(m.empty()); @@ -60,6 +66,32 @@ int main(int, char**) { assert(m.key_comp().default_constructed_); } } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp deleted file mode 100644 index b4a3b6de205a31..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set() -// noexcept( -// is_nothrow_default_constructible_v && -// is_nothrow_default_constructible_v); - -// This tests a conforming extension - -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -struct ThrowingCtorComp { - ThrowingCtorComp() noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -int main(int, char**) { -#if defined(_LIBCPP_VERSION) - { - using C = std::flat_set; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set, std::vector>>; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } -#endif // _LIBCPP_VERSION - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp index c0d315c0ce74b4..fa1e2478af4599 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -27,7 +27,7 @@ struct ThrowingDtorComp { ~ThrowingDtorComp() noexcept(false) {} }; -int main(int, char**) { +void test() { { using C = std::flat_set; static_assert(std::is_nothrow_destructible_v); @@ -52,6 +52,10 @@ int main(int, char**) { C c; } #endif // _LIBCPP_VERSION +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp index cd2319e91f760d..9aed5c88ee7268 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -35,7 +35,7 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -146,6 +146,10 @@ int main(int, char**) { M m({5, 2, 2, 3, 1, 3}, {}, a); assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp index 65eebc21a66c4c..2d0b07c9155fdb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -29,7 +29,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -131,6 +131,10 @@ int main(int, char**) { LIBCPP_ASSERT(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp index 69b340ad09fe15..b2853844b986c6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -25,7 +25,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; using A = test_allocator; @@ -79,5 +79,110 @@ int main(int, char**) { LIBCPP_ASSERT(m1.empty()); LIBCPP_ASSERT(m1.size() == 0); } +} + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +void test_move_noexcept() { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +} + +#if !defined(TEST_HAS_NO_EXCEPTIONS) +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +void test_move_exception() { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } +} +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + +int main(int, char**) { + test(); + test_move_noexcept(); +#if !defined(TEST_HAS_NO_EXCEPTIONS) + test_move_exception(); +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp index fc7f68d8c967ad..489b6ff36324b3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -53,7 +53,7 @@ int main(int, char**) { assert(m.size() == 3); auto keys = std::move(m).extract(); assert(keys.get_allocator() == A(3)); - assert(std::ranges::equal(keys, expected )); + assert(std::ranges::equal(keys, expected)); // The original flat_set is moved-from. assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); @@ -63,13 +63,17 @@ int main(int, char**) { } { // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, CopyOnlyVector>; + using M = std::flat_set, CopyOnlyVector>; M m1 = M({1, 2, 3}); M m2(std::move(m1), std::allocator{}); assert(m2.size() == 3); check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index b16dc38dd40285..e55a0516ed1bed 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -22,11 +22,144 @@ #include "test_macros.h" #include "MoveOnly.h" +#include "../helpers.h" #include "../../../test_compare.h" #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +void test_move_assign_clears() { + // Preserves the class invariant for the moved-from flat_set. + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } +} + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +void test_move_assign_no_except() { + // This tests a conforming extension + + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } +} + +void test() { { using C = test_less; using A1 = test_allocator; @@ -64,6 +197,12 @@ int main(int, char**) { assert(ks.get_allocator() == A()); assert(mo.empty()); } +} + +int main(int, char**) { + test(); + test_move_assign_clears(); + test_move_assign_no_except(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp deleted file mode 100644 index 50817f4be8a812..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&&); -// Preserves the class invariant for the moved-from flat_set. - -#include -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -struct MoveNegates { - int value_ = 0; - MoveNegates() = default; - MoveNegates(int v) : value_(v) {} - MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } - MoveNegates& operator=(MoveNegates&& rhs) { - value_ = rhs.value_; - rhs.value_ = -rhs.value_; - return *this; - } - ~MoveNegates() = default; - auto operator<=>(const MoveNegates&) const = default; -}; - -struct MoveClears { - int value_ = 0; - MoveClears() = default; - MoveClears(int v) : value_(v) {} - MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } - MoveClears& operator=(MoveClears&& rhs) { - value_ = rhs.value_; - rhs.value_ = 0; - return *this; - } - ~MoveClears() = default; - auto operator<=>(const MoveClears&) const = default; -}; - -int main(int, char**) { - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, std::vector>; - M m1 = M({1, 2, 3}); - M m2 = M({1, 2}); - m2 = std::move(m1); - assert(m2.size() == 3); - check_invariant(m1); - LIBCPP_ASSERT(m1.empty()); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp deleted file mode 100644 index 86f3568f0d67a6..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&& c) -// noexcept( -// is_nothrow_move_assignable::value && -// is_nothrow_move_assignable::value && -// is_nothrow_copy_assignable::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include - -#include "MoveOnly.h" -#include "test_allocator.h" -#include "test_macros.h" - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -struct MoveThrowsComp { - MoveThrowsComp(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp(const MoveThrowsComp&) noexcept(true); - MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); - bool operator()(const auto&, const auto&) const; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - // Test with a comparator that throws on move-assignment. - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); - } - { - // Test with a container that throws on move-assignment. - using C = std::flat_set, std::pmr::vector>; - static_assert(!std::is_nothrow_move_assignable_v); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp deleted file mode 100644 index 17e4e40387606c..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 -// UNSUPPORTED: no-exceptions - -// - -// flat_set(flat_set&& s); -// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. - -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -static int countdown = 0; - -struct EvilContainer : std::vector { - EvilContainer() = default; - EvilContainer(EvilContainer&& rhs) { - // Throw on move-construction. - if (--countdown == 0) { - rhs.insert(rhs.end(), 0); - rhs.insert(rhs.end(), 0); - throw 42; - } - } -}; - -int main(int, char**) { - { - using M = std::flat_set, EvilContainer>; - M mo = {1, 2, 3}; - countdown = 1; - try { - M m = std::move(mo); - assert(false); // not reached - } catch (int x) { - assert(x == 42); - } - // The source flat_set maintains its class invariant. - check_invariant(mo); - LIBCPP_ASSERT(mo.empty()); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp deleted file mode 100644 index 49d1151fd8a993..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set(flat_set&&) -// noexcept(is_nothrow_move_constructible::value && -// is_nothrow_move_constructible::value && -// is_nothrow_copy_constructible::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -template -struct ThrowingMoveAllocator { - using value_type = T; - explicit ThrowingMoveAllocator() = default; - ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; - ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} - T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } - void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } - friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; -}; - -struct ThrowingMoveComp { - ThrowingMoveComp() = default; - ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} - ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - { - using C = std::flat_set, std::deque>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#if _LIBCPP_VERSION - { - // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators - using C = std::flat_set, std::deque>>; - static_assert(!std::is_nothrow_move_constructible_v>>); - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#endif // _LIBCPP_VERSION - { - // Comparator fails to be nothrow-move-constructible - using C = std::flat_set; - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp index 785718d2eed333..1a4eafa8802918 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -28,7 +28,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // flat_set(const Allocator& a); using M = std::flat_set, std::pmr::vector>; @@ -317,6 +317,10 @@ int main(int, char**) { assert(vm[0].key_comp() == C(4)); assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp index bb9f99c228bfec..bd7b5c12432e96 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -56,7 +56,7 @@ static_assert( !std:: is_constructible_v>, std::less, std::allocator>); -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -168,6 +168,10 @@ int main(int, char**) { assert(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp index 2d442d49667bd0..873ff32b62936a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -138,6 +138,10 @@ int main(int, char**) { assert(m2 == m); assert(std::move(m2).extract().get_allocator() == A(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp index 01956a78c7f48d..a8dac35aefee81 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -33,10 +33,10 @@ template std::initializer_list il = {1, 2, 4, 5}; -const auto il1 = il; -const auto il2 = il; +void test() { + const auto il1 = il; + const auto il2 = il; -int main(int, char**) { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -145,6 +145,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp index b5229a84dd5133..b184ee9c3f5aba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -28,7 +28,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -151,6 +151,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp index 134db83aef3cad..806779bc7d16bc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -49,7 +49,7 @@ void test0( } template -void test() { +void test_one() { // Test all the plausible signatures for this predicate. auto is1 = [](typename S::const_reference v) { return v == 1; }; auto is2 = [](typename S::value_type v) { return v == 2; }; @@ -76,14 +76,18 @@ void test() { test0({1, 2, 3}, False, {1, 2, 3}, 0); } +void test() { + test_one>(); + test_one, std::vector>>>(); + test_one, std::vector>>>(); + test_one, std::deque>>>(); + test_one, std::deque>>>(); + test_one>(); + test_one>(); +} + int main(int, char**) { - test>(); - test, std::vector>>>(); - test, std::vector>>>(); - test, std::deque>>>(); - test, std::deque>>>(); - test>(); - test>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp index 6bbe1ad4f01670..37b4a40f0165cf 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -65,7 +65,7 @@ struct ErasurePredicate { bool operator()(const auto& x) const { return (3 <= x && x <= 5); } }; -int main(int, char**) { +void test() { const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; { using M = std::flat_set; @@ -124,5 +124,10 @@ int main(int, char**) { } } } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp index c07297a141ad10..846bcff63d7736 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -30,7 +30,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -67,15 +67,15 @@ void test() { assert(i == m.begin()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::iterator ii1{}, ii2{}; C::iterator ii4 = ii1; C::const_iterator cii{}; @@ -88,6 +88,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp index 29441dcc57d40e..3027cdd4076eea 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using KI = typename KeyContainer::iterator; @@ -144,11 +144,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp index a16383cdcf5383..d1e4cef3de19e8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include -int main(int, char**) { +void test() { { using M = std::flat_set, std::deque>; M m = {1, 2, 3, 4}; @@ -69,7 +69,7 @@ int main(int, char**) { } { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::reverse_iterator ii1{}, ii2{}; C::reverse_iterator ii4 = ii1; C::const_reverse_iterator cii{}; @@ -82,6 +82,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp index 221a13fa057577..efa13a51c30bb3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -38,7 +38,7 @@ static_assert(NoExceptClear, ThrowOnMoveContai #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -50,13 +50,17 @@ void test() { assert(m.size() == 0); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp index 95f7a3c5f5d34a..79800e894afbfc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -28,7 +28,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -121,21 +121,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp index de855d5e5c3009..b3bd8adf0c35d8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -27,7 +27,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = M::iterator; @@ -134,21 +134,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp index 386af04d26e9a2..42562b84b4e22d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -27,7 +27,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -106,16 +106,21 @@ void test() { assert(i8 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp index 7416977844e5df..d402a7ba0285ec 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -77,15 +77,21 @@ void test() { assert(i4 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp index 25d4f4af19608b..d81422d3871876 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template > -void test() { +void test_one() { using M = std::flat_set; auto make = [](std::initializer_list il) { @@ -70,22 +70,27 @@ void test() { assert(m.empty()); } -int main(int, char**) { - test>(); - test, std::greater<>>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one, std::greater<>>(); + test_one>(); + test_one>(); + test_one>>(); +} - { - auto erase_function = [](auto& m, auto key_arg) { - using Map = std::decay_t; - using Key = typename Map::key_type; - const Key key{key_arg}; - m.erase(key); - }; - test_erase_exception_guarantee(erase_function); - } +void test_exception() { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp index cbf7cac603806d..c383844eb4973e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -50,7 +50,7 @@ struct HeterogeneousKey { }; template -void test_simple() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -86,11 +86,11 @@ void test_transparent_comparator() { assert(m == expected); } -int main(int, char**) { - test_simple>(); - test_simple>(); - test_simple>(); - test_simple>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_transparent_comparator>(); test_transparent_comparator>(); @@ -129,14 +129,20 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } - { - auto erase_transparent = [](auto& m, auto key_arg) { - using Set = std::decay_t; - using Key = typename Set::key_type; - m.erase(Transparent{key_arg}); - }; - test_erase_exception_guarantee(erase_transparent); - } +} + +void test_exception() { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp index c3bbffabb90a08..dfa21a807f0254 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -33,7 +33,7 @@ static_assert(!CanExtract const&>); static_assert(!CanExtract const&&>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; M m = M({1, 2, 3}); @@ -45,11 +45,12 @@ void test() { LIBCPP_ASSERT(m.empty()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { // extracted object maintains invariant if the underlying container does not clear after move using M = std::flat_set, CopyOnlyVector>; @@ -59,7 +60,9 @@ int main(int, char**) { check_invariant(m); LIBCPP_ASSERT(m.empty()); } +} +void test_exception() { { #ifndef TEST_HAS_NO_EXCEPTIONS using KeyContainer = ThrowOnMoveContainer; @@ -79,5 +82,11 @@ int main(int, char**) { } #endif } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp index c0ddadc3006987..e0cb80f74462cd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -59,20 +59,25 @@ void test() { assert(*r.first == 3); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using value_type = typename std::decay_t::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(p); - }; - test_emplace_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp index 7381514a70eabb..bf94fd9f5b11fd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -23,12 +23,12 @@ #include "min_allocator.h" template -void test() { - using Key = typename KeyContainer::value_type; - using M = std::flat_set, KeyContainer>; - using V = typename M::value_type; +void test_one() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; - M m = {1,1,1,3,3,3}; + M m = {1, 1, 1, 3, 3, 3}; m.insert({ 4, 4, @@ -48,20 +48,26 @@ void test() { assert(*std::next(m.begin(), 3) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(il); - }; - test_insert_range_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index c343d53a62215a..d6791853e0debd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = typename M::iterator; @@ -55,13 +55,15 @@ void test() { assert(*r == 3); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; using value_type = typename FlatSet::value_type; @@ -69,6 +71,11 @@ int main(int, char**) { m.insert(m.begin(), p); }; test_emplace_exception_guarantee(insert_func); - } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp index d20a8ef8fdd92d..8063686c960ed3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; int ar1[] = { @@ -73,15 +73,22 @@ void test() { M expected2{0, 1, 2, 3, 4}; assert(m == expected2); } + +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp index 84b6c7fc1d34f6..d29de98e4d3ddb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -22,7 +22,7 @@ #include "test_macros.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -49,25 +49,30 @@ void test() { assert(*r == V(3)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(m.begin(), std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp index 536307252c6405..ed33827a7355c9 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -39,7 +39,7 @@ static_assert(!CanInsertRange*>>) static_assert(!CanInsertRange*>>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -75,31 +75,29 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { - // Items are forwarded correctly from the input range (P2767). + // Items are forwarded correctly from the input range. MoveOnly a[] = {3, 1, 4, 1, 5}; std::flat_set m; m.insert_range(a | std::views::as_rvalue); MoveOnly expected[] = {1, 3, 4, 5}; assert(std::ranges::equal(m, expected)); } - { - // The element type of the range doesn't need to be std::pair (P2767). - int pa[] = {3, 1, 4, 1, 5}; - std::deque> a(pa, pa + 5); - std::flat_set m; - m.insert_range(a); - int expected[] = {1, 3, 4, 5}; - assert(std::ranges::equal(m, expected)); - } - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; - test_insert_range_exception_guarantee(insert_func); - } +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp index 7d95f0521eb1f6..faf74142caff5c 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -25,7 +25,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; using R = std::pair; @@ -57,24 +57,30 @@ void test() { assert(*r.first == V(3)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp index fa5bf86830daec..38c36d1befaa7c 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -38,21 +38,26 @@ void test() { assert(*std::next(m.begin(), 4) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(std::sorted_unique, il); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp index ef7b8391cee33c..6258c4dbfdcbba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -60,18 +60,23 @@ void test() { assert(m == expected2); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - m.insert(std::sorted_unique, newValues.begin(), newValues.end()); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp index 72d7261a182547..d2ddf95aac2bb7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -57,7 +57,7 @@ struct CompareCounter { }; template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -121,11 +121,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // no ambiguity between insert(pos, P&&) and insert(first, last) @@ -139,6 +139,9 @@ int main(int, char**) { ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); } +} + +void test_exception() { { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; @@ -165,5 +168,11 @@ int main(int, char**) { }; test_emplace_exception_guarantee(insert_func_iter); } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp index 49cb6eb6163c90..fca33bd41449e0 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -31,7 +31,7 @@ static_assert(CanReplace>); static_assert(!CanReplace&>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -43,30 +43,36 @@ void test() { assert(std::ranges::equal(m, expected_keys)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { #ifndef TEST_HAS_NO_EXCEPTIONS - using KeyContainer = ThrowOnMoveContainer; - using M = std::flat_set; + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; - M m; - m.emplace(1); - m.emplace(2); - try { - KeyContainer new_keys{3, 4}; - m.replace(std::move(new_keys)); - assert(false); - } catch (int) { - check_invariant(m); - // In libc++, we clear the map - LIBCPP_ASSERT(m.size() == 0); - } -#endif + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); } +#endif +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp index bc7baa67e52a59..ed13ba1ef3fea7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -24,6 +24,8 @@ #include "test_macros.h" #include "../helpers.h" +#include "check_assertion.h" + // test noexcept template @@ -38,7 +40,7 @@ static_assert(NoExceptAdlSwap, ThrowOnMoveCont #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -84,11 +86,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp index b0b06a9499efc7..1eac55d768ce0b 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -37,7 +37,7 @@ static_assert(NoExceptMemberSwap, ThrowOnMoveC #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -82,11 +82,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp index 971b5e1c338dd1..ba2c428c9e30e2 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -21,7 +21,7 @@ #include "test_macros.h" -int main(int, char**) { +void test() { { using M = std::flat_set; using Comp = std::less; // the default @@ -67,6 +67,10 @@ int main(int, char**) { assert(vc(1, 2)); assert(!vc(2, 1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp index b14da66f611301..e23683f6f28945 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp index 507560608952b0..0cdff44d11274f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanContains); static_assert(!CanContains); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.contains(Transparent{"g"}) == false); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,5 +66,10 @@ int main(int, char**) { assert(b); assert(transparent_used); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp index 478f615358b606..017f0fed3e9816 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using S = typename KeyContainer::size_type; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp index b591258f74399c..0c5ce9d5799651 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanCount); static_assert(!CanCount); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.count(Transparent{"g"}) == 0); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,6 +66,10 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp index a088b7fee17d2c..b55cbe2ac42a00 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -67,11 +67,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp index ede5d91e19b9fd..97c4af19eaef37 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanEqualRange); static_assert(!CanEqualRange); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -77,11 +77,11 @@ void test() { test_not_found(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -92,6 +92,10 @@ int main(int, char**) { assert(p.first != p.second); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp index cf0dd2d1dd831c..9ee8f043e1d9cd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -25,7 +25,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m = {1, 2, 4, 5, 8}; @@ -43,11 +43,15 @@ void test() { assert(std::as_const(m).find(9) == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp index 730a57b0a6cb85..cc8ea12bcf4a6a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanFind); static_assert(!CanFind); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -68,11 +68,11 @@ void test() { test_find(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -83,6 +83,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp index 093c32e537ed35..1ceddb2f1c9d26 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -60,11 +60,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp index 18f9bc6dd32955..19991ca05fbc8a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanLowerBound); static_assert(!CanLowerBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,11 @@ void test() { test_lower_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -89,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp index ab34de85103175..f25896e1229397 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -61,11 +61,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp index 69ce2ae926a305..c9b519d2032193 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanUpperBound); static_assert(!CanUpperBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,12 @@ void test() { test_upper_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { bool transparent_used = false; TransparentComparator c(transparent_used); @@ -88,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h index 9fff262d84234e..2ee8b021337a06 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SUPPORT_flat_set_HELPERS_H -#define SUPPORT_flat_set_HELPERS_H +#ifndef SUPPORT_FLAT_SET_HELPERS_H +#define SUPPORT_FLAT_SET_HELPERS_H #include #include @@ -149,6 +149,19 @@ struct EmplaceUnsafeContainer : std::vector { throw 42; } + + template + auto insert_range(Args&&... args) + -> decltype(std::declval>().insert_range(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } }; template @@ -291,4 +304,4 @@ class Moveable { bool moved() const { return int_ == -1; } }; -#endif // SUPPORT_flat_set_HELPERS_H +#endif // SUPPORT_FLAT_SET_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp index c4a9810016536b..faf746861df309 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -27,7 +27,10 @@ struct A { // Implement the operator< required in order to instantiate flat_set bool operator<(A const& L, A const& R) { return L.data < R.data; } +void test() { A a; } + int main(int, char**) { - A a; + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp index f6d08bb736d300..3e7aecee77fdd8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -31,7 +31,7 @@ #include "test_container_comparisons.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -69,11 +69,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { using C = std::flat_set; @@ -101,5 +101,10 @@ int main(int, char**) { assert(s1 != s2); assert((s1 <=> s2) == std::partial_ordering::unordered); } +} + +int main(int, char**) { + test(); + return 0; } >From 6fa4b5763cccee5d1631d9239c12f33d5c656956 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 14:08:01 +0000 Subject: [PATCH 3/6] review --- .../flat.set/assert.sorted_unique.pass.cpp | 226 ++++++++++++++++++ .../assign_initializer_list.pass.cpp | 6 +- .../flat.set.cons/move_assign.pass.cpp | 67 ++++-- 3 files changed, 280 insertions(+), 19 deletions(-) create mode 100644 libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp diff --git a/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp new file mode 100644 index 00000000000000..62903af7f4e477 --- /dev/null +++ b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp @@ -0,0 +1,226 @@ +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: libcpp-hardening-mode=none +// REQUIRES: libcpp-hardening-mode=debug +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// + +// flat_set(container_type , const key_compare& __comp = key_compare()) +// flat_set(const container_type& , const _Allocator& ) +// flat_set(const container_type& , const key_compare&, const _Allocator& ) +// void replace(container_type&& ) +// + +#include +#include +#include +#include +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + using M = std::flat_set; + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{1, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{2, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7e948d7c5fe976..ad49b621490366 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -30,14 +30,16 @@ void test_one() { { M m = {8, 10}; assert(m.size() == 2); - m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + std::same_as decltype(auto) r = m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + assert(&r == &m); int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); } { M m = {10, 8}; assert(m.size() == 2); - m = {3}; + std::same_as decltype(auto) r = m = {3}; + assert(&r == &m); int expected[] = {3}; assert(std::ranges::equal(m, expected)); } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index e55a0516ed1bed..0e0ab0aa135f9f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -55,6 +55,19 @@ struct MoveClears { auto operator<=>(const MoveClears&) const = default; }; +#if !defined(TEST_HAS_NO_EXCEPTIONS) +struct MoveAssignThrows : std::vector { + using std::vector::vector; + MoveAssignThrows& operator=(MoveAssignThrows&& other) { + push_back(0); + push_back(0); + other.push_back(0); + other.push_back(0); + throw 42; + } +}; +#endif // TEST_HAS_NO_EXCEPTIONS + void test_move_assign_clears() { // Preserves the class invariant for the moved-from flat_set. { @@ -101,6 +114,23 @@ void test_move_assign_clears() { check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +#if !defined(TEST_HAS_NO_EXCEPTIONS) + { + using M = std::flat_set, MoveAssignThrows>; + M m1 = {1, 2, 3}; + M m2 = {1, 2}; + try { + m2 = std::move(m1); + assert(false); + } catch (int e) { + assert(e == 42); + } + check_invariant(m1); + check_invariant(m2); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m2.empty()); + } +#endif // TEST_HAS_NO_EXCEPTIONS } struct MoveSensitiveComp { @@ -161,12 +191,13 @@ void test_move_assign_no_except() { void test() { { - using C = test_less; - using A1 = test_allocator; - using M = std::flat_set>; - M mo = M({1, 2, 3}, C(5), A1(7)); - M m = M({}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{1, 2, 3})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -174,12 +205,13 @@ void test() { assert(mo.empty()); } { - using C = test_less; - using A1 = other_allocator; - using M = std::flat_set>; - M mo = M({4, 5}, C(5), A1(7)); - M m = M({1, 2, 3, 4}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{4, 5})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -187,11 +219,12 @@ void test() { assert(mo.empty()); } { - using A = min_allocator; - using M = std::flat_set, std::vector>; - M mo = M({5, 4, 3}, A()); - M m = M({4, 3, 2, 1}, A()); - m = std::move(mo); + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{5, 4, 3})); auto ks = std::move(m).extract(); assert(ks.get_allocator() == A()); >From c65a37ea8012b92dc5575be91a1a18851a8caeaa Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 16:23:56 +0000 Subject: [PATCH 4/6] clang-format --- .../flat.set/flat.set.capacity/max_size.pass.cpp | 1 - .../flat.set.modifiers/insert_iter_cv.pass.cpp | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index 0489d886257911..dde1f7092e5b18 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -25,7 +25,6 @@ #include "test_macros.h" void test() { - { using A1 = limited_allocator; using C = std::flat_set, std::vector>; diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index d6791853e0debd..76b4d5f0eb7cc6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -56,7 +56,6 @@ void test_one() { } void test() { - test_one>(); test_one>(); test_one>(); @@ -64,13 +63,13 @@ void test() { } void test_exception() { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(m.begin(), p); - }; - test_emplace_exception_guarantee(insert_func); + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); } int main(int, char**) { >From 61147247cfcf3fd4623587bddaa07a2c4783d2b6 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 16:59:41 +0000 Subject: [PATCH 5/6] CI --- libcxx/docs/ReleaseNotes/21.rst | 1 + libcxx/docs/Status/Cxx23Papers.csv | 2 +- libcxx/modules/std.compat.cppm.in | 3 - libcxx/modules/std.cppm.in | 4 +- libcxx/modules/std/flat_set.inc | 4 +- .../test/libcxx/transitive_includes/cxx03.csv | 8 ++ .../test/libcxx/transitive_includes/cxx11.csv | 8 ++ .../test/libcxx/transitive_includes/cxx14.csv | 8 ++ .../test/libcxx/transitive_includes/cxx17.csv | 8 ++ .../test/libcxx/transitive_includes/cxx20.csv | 8 ++ .../test/libcxx/transitive_includes/cxx23.csv | 15 +++- .../test/libcxx/transitive_includes/cxx26.csv | 14 ++++ .../flat_set.version.compile.pass.cpp | 80 +++++++++++++++++++ libcxx/utils/libcxx/header_information.py | 2 +- 14 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad3942..0c1029f50a6fe7 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -39,6 +39,7 @@ Implemented Papers ------------------ - N4258: Cleaning-up noexcept in the Library (`Github `__) +- P1222R4: A Standard ``flat_set`` is partially implemented and ``flat_set`` is provided (`Github `__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 264c5417a5c28b..bcd9c5c43a9c69 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -54,7 +54,7 @@ "`P0009R18 `__","mdspan: A Non-Owning Multidimensional Array Reference","2022-07 (Virtual)","|Complete|","18","" "`P0429R9 `__","A Standard ``flat_map``","2022-07 (Virtual)","|Complete|","20","" "`P1169R4 `__","``static operator()``","2022-07 (Virtual)","|Complete|","16","" -"`P1222R4 `__","A Standard ``flat_set``","2022-07 (Virtual)","","","" +"`P1222R4 `__","A Standard ``flat_set``","2022-07 (Virtual)","|In progress|","","" "`P1223R5 `__","``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()``","2022-07 (Virtual)","|Complete|","19","" "`P1467R9 `__","Extended ``floating-point`` types and standard names","2022-07 (Virtual)","","","" "`P1642R11 `__","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","2022-07 (Virtual)","","","" diff --git a/libcxx/modules/std.compat.cppm.in b/libcxx/modules/std.compat.cppm.in index 5cea1b75bfc170..95931447ccdc64 100644 --- a/libcxx/modules/std.compat.cppm.in +++ b/libcxx/modules/std.compat.cppm.in @@ -53,9 +53,6 @@ module; # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in index b9d00df70658d8..5c523691bff4e2 100644 --- a/libcxx/modules/std.cppm.in +++ b/libcxx/modules/std.cppm.in @@ -65,6 +65,7 @@ module; #include #include #include +#include #include #include #if _LIBCPP_HAS_LOCALIZATION @@ -162,9 +163,6 @@ module; # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std/flat_set.inc b/libcxx/modules/std/flat_set.inc index a86cc1eae02a62..3f2c6e09a0ebe4 100644 --- a/libcxx/modules/std/flat_set.inc +++ b/libcxx/modules/std/flat_set.inc @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// export namespace std { -#if 0 +#if _LIBCPP_STD_VER >= 23 // [flat.set], class template flat_­set using std::flat_set; @@ -19,7 +19,9 @@ export namespace std { // [flat.set.erasure], erasure for flat_­set using std::erase_if; +#endif // _LIBCPP_STD_VER >= 23 +#if 0 // [flat.multiset], class template flat_­multiset using std::flat_multiset; diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv index ec5db90597d927..c0031543e47bce 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -683,6 +683,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv index ec5db90597d927..c0031543e47bce 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -683,6 +683,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv index 95024df0590b84..c2eb5b44e8d7a7 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -701,6 +701,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv index a3518f7f62ecb9..332cb62f35b5f4 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -709,6 +709,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv index 6de95139279471..55c79acff5a8f9 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -705,6 +705,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv index 17972b84537436..7da07a8b3749b2 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -345,6 +345,20 @@ flat_map optional flat_map stdexcept flat_map tuple flat_map version +flat_set cctype +flat_set climits +flat_set compare +flat_set cstdint +flat_set cstring +flat_set cwchar +flat_set cwctype +flat_set initializer_list +flat_set limits +flat_set optional +flat_set stdexcept +flat_set tuple +flat_set type_traits +flat_set version format array format cctype format cerrno @@ -556,7 +570,6 @@ istream ios istream iosfwd istream limits istream locale - istream ratio istream stdexcept istream streambuf diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv index 00ab78e61a4576..4c2782a4ce5cf9 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -345,6 +345,20 @@ flat_map optional flat_map stdexcept flat_map tuple flat_map version +flat_set cctype +flat_set climits +flat_set compare +flat_set cstdint +flat_set cstring +flat_set cwchar +flat_set cwctype +flat_set initializer_list +flat_set limits +flat_set optional +flat_set stdexcept +flat_set tuple +flat_set type_traits +flat_set version format array format cctype format cerrno diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp new file mode 100644 index 00000000000000..f9d0b0a6b4e4f6 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. +// +// clang-format off + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_flat_set 202207L [C++23] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should be defined in c++23" +# endif +# if __cpp_lib_flat_set != 202207L +# error "__cpp_lib_flat_set should have the value 202207L in c++23" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#elif TEST_STD_VER > 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should be defined in c++26" +# endif +# if __cpp_lib_flat_set != 202207L +# error "__cpp_lib_flat_set should have the value 202207L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#endif // TEST_STD_VER > 23 + diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py index 9a723b61524cd5..9811b42d510ca3 100644 --- a/libcxx/utils/libcxx/header_information.py +++ b/libcxx/utils/libcxx/header_information.py @@ -164,7 +164,6 @@ def __hash__(self) -> int: # modules will fail to build if a header is added but this list is not updated. headers_not_available = list(map(Header, [ "debugging", - "flat_set", "generator", "hazard_pointer", "inplace_vector", @@ -261,6 +260,7 @@ def __hash__(self) -> int: "deque": ["compare", "initializer_list"], "filesystem": ["compare"], "flat_map": ["compare", "initializer_list"], + "flat_set": ["compare", "initializer_list"], "forward_list": ["compare", "initializer_list"], "ios": ["iosfwd"], "iostream": ["ios", "istream", "ostream", "streambuf"], >From a7583dad7798ec3f4259a2bcd4e851a85c7e04d6 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 18:05:17 +0000 Subject: [PATCH 6/6] deduction --- .../flat.set.cons/deduct.compile.pass.cpp | 14 +- .../flat.set/flat.set.cons/deduct.pass.cpp | 239 +++++++++--------- 2 files changed, 121 insertions(+), 132 deletions(-) diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp index 5db8c4ca722466..1161fe6e61c78e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp @@ -23,27 +23,21 @@ struct NotAnAllocator { }; template -concept CanDeductFlatSet = requires { std::flat_set{std::declval()...}; }; +concept CanDeductFlatSet = requires { std::flat_set(std::declval()...); }; -static_assert(CanDeductFlatSet, std::vector>); +static_assert(CanDeductFlatSet>); // cannot deduce Key and T from nothing static_assert(!CanDeductFlatSet<>); -// cannot deduce Key and T from just (KeyContainer), even if it's a container of pairs -static_assert(!CanDeductFlatSet>>); - -// cannot deduce Key and T from just (KeyContainer, Allocator) -static_assert(!CanDeductFlatSet, std::allocator>>); - // cannot deduce Key and T from just (Compare) static_assert(!CanDeductFlatSet>); // cannot deduce Key and T from just (Compare, Allocator) -static_assert(!CanDeductFlatSet, std::allocator>); +static_assert(!CanDeductFlatSet, std::allocator>); // cannot deduce Key and T from just (Allocator) -static_assert(!CanDeductFlatSet>); +static_assert(!CanDeductFlatSet>); // cannot convert from some arbitrary unrelated type static_assert(!CanDeductFlatSet); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp index 607fe0d1a9713a..491c77d3737af1 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -116,8 +116,8 @@ void test_containers_compare() { } void test_iter_iter() { - const int arr[] = {1, 2, 1, INT_MAX, 3}; - const int sorted_arr[] = {1, 2, 3, INT_MAX}; + int arr[] = {1, 2, 1, INT_MAX, 3}; + int sorted_arr[] = {1, 2, 3, INT_MAX}; const int arrc[] = {1, 2, 1, INT_MAX, 3}; const int sorted_arrc[] = {1, 2, 3, INT_MAX}; { @@ -154,6 +154,12 @@ void test_iter_iter() { std::flat_set m(mo.cbegin(), mo.cend()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } + { + int source[3] = {1, 2, 3}; + std::flat_set s(source, source + 3); + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } { // This does not deduce to flat_set(InputIterator, InputIterator) // But deduces to flat_set(initializer_list) @@ -171,140 +177,125 @@ void test_iter_iter() { } void test_iter_iter_compare() { - // const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - // const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // using C = std::greater; - // { - // std::flat_set m(std::begin(arr), std::end(arr), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::begin(arrc), std::end(arrc), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set mo; - // std::flat_set m(mo.begin(), mo.end(), C()); - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // } - // { - // std::flat_set mo; - // std::flat_set m(mo.cbegin(), mo.cend(), C()); - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // } + int arr[] = {1, 2, 1, INT_MAX, 3}; + int sorted_arr[] = {INT_MAX, 3, 2, 1}; + const int arrc[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arrc[] = {INT_MAX, 3, 2, 1}; + using C = std::greater; + { + std::flat_set m(std::begin(arr), std::end(arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } } void test_initializer_list() { - // const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - // { - // std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) - // ASSERT_SAME_TYPE(decltype(s), std::flat_set); - // assert(s.size() == 1); - // } - // { - // using M = std::flat_set; - // M m; - // std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) - // ASSERT_SAME_TYPE(decltype(s), std::flat_set); - // assert(s.size() == 1); - // assert(s[m] == m); - // } + const int sorted_arr[] = {1, 2, 3, INT_MAX}; + { + std::flat_set m{1, 2, 1, INT_MAX, 3}; + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {1, 2, 3, INT_MAX}); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set s = {1}; + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } + { + using M = std::flat_set; + M m; + std::flat_set s{m, m}; // flat_set(initializer_list) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } } void test_initializer_list_compare() { - // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // using C = std::greater; - // { - // std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } + const int sorted_arr[] = {INT_MAX, 3, 2, 1}; + using C = std::greater; + { + std::flat_set m({1, 2, 1, INT_MAX, 3}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {INT_MAX, 3, 2, 1}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } } void test_from_range() { - // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - // const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; - // { - // std::flat_set s(std::from_range, r); - // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - // assert(std::ranges::equal(s, expected)); - // } - // { - // std::flat_set s(std::from_range, r, test_allocator(0, 42)); - // ASSERT_SAME_TYPE( - // decltype(s), - // std::flat_set, - // std::vector>, - // std::vector>>); - // assert(std::ranges::equal(s, expected)); - // assert(s.keys().get_allocator().get_id() == 42); - // assert(s.values().get_allocator().get_id() == 42); - // } + std::list r = {1, 2, 1, INT_MAX, 3}; + const int expected[] = {1, 2, 3, INT_MAX}; + { + std::flat_set s(std::from_range, r); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, test_allocator(0, 42)); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(std::move(s).extract().get_allocator().get_id() == 42); + } } void test_from_range_compare() { - // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - // const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; - // { - // std::flat_set s(std::from_range, r, std::greater()); - // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - // assert(std::ranges::equal(s, expected)); - // } - // { - // std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); - // ASSERT_SAME_TYPE( - // decltype(s), - // std::flat_set, - // std::vector>, - // std::vector>>); - // assert(std::ranges::equal(s, expected)); - // assert(s.keys().get_allocator().get_id() == 42); - // assert(s.values().get_allocator().get_id() == 42); - // } + std::list r = {1, 2, 1, INT_MAX, 3}; + const int expected[] = {INT_MAX, 3, 2, 1}; + { + std::flat_set s(std::from_range, r, std::greater()); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(std::move(s).extract().get_allocator().get_id() == 42); + } } -int main(int, char**) { +void test() { // Each test function also tests the sorted_unique-prefixed and allocator-suffixed overloads. test_copy(); test_containers(); @@ -317,6 +308,10 @@ int main(int, char**) { test_from_range_compare(); AssociativeContainerDeductionGuidesSfinaeAway>(); +} + +int main(int, char**) { + test(); return 0; } From libcxx-commits at lists.llvm.org Sun Feb 2 10:13:54 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Sun, 02 Feb 2025 10:13:54 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Simplify vector::__construct_at_end (Reopend) (PR #119632) In-Reply-To: Message-ID: <679fb5e2.170a0220.24e1b1.218e@mx.google.com> ================ @@ -552,36 +552,29 @@ vector::__recommend(size_type __new_size) const { } // Default constructs __n objects starting at __end_ -// Precondition: __n > 0 // Precondition: size() + __n <= capacity() // Postcondition: size() == size() + __n template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__construct_at_end(size_type __n, bool __x) { - size_type __old_size = this->__size_; + _LIBCPP_ASSERT_INTERNAL( + capacity() >= size() + __n, "vector::__construct_at_end called with insufficient capacity"); + std::fill_n(end(), __n, __x); this->__size_ += __n; - if (__old_size == 0 || ((__old_size - 1) / __bits_per_word) != ((this->__size_ - 1) / __bits_per_word)) { - if (this->__size_ <= __bits_per_word) - this->__begin_[0] = __storage_type(0); - else - this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0); - } - std::fill_n(__make_iter(__old_size), __n, __x); + if (end().__ctz_ != 0) // Ensure uninitialized leading bits in the last word are set to zero + std::fill_n(end(), __bits_per_word - end().__ctz_, 0); } template template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n) { ---------------- winner245 wrote: I understand your concern here. That's why I explicitly check if we have uninitialized bits, which could only exist in the last partial word. Previously, we pre-initialize the entire last word, whether it is a partial word or not. This patch implements it in a more compact form which initializes the bits to zero only when the last word is a partial word. https://github.com/llvm/llvm-project/pull/119632 From libcxx-commits at lists.llvm.org Sun Feb 2 10:36:26 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 10:36:26 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Simplify vector::__construct_at_end (Reopend) (PR #119632) In-Reply-To: Message-ID: <679fbb2a.630a0220.2dbf96.39a9@mx.google.com> ================ @@ -552,36 +552,29 @@ vector::__recommend(size_type __new_size) const { } // Default constructs __n objects starting at __end_ -// Precondition: __n > 0 // Precondition: size() + __n <= capacity() // Postcondition: size() == size() + __n template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__construct_at_end(size_type __n, bool __x) { - size_type __old_size = this->__size_; + _LIBCPP_ASSERT_INTERNAL( + capacity() >= size() + __n, "vector::__construct_at_end called with insufficient capacity"); + std::fill_n(end(), __n, __x); this->__size_ += __n; - if (__old_size == 0 || ((__old_size - 1) / __bits_per_word) != ((this->__size_ - 1) / __bits_per_word)) { - if (this->__size_ <= __bits_per_word) - this->__begin_[0] = __storage_type(0); - else - this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0); - } - std::fill_n(__make_iter(__old_size), __n, __x); + if (end().__ctz_ != 0) // Ensure uninitialized leading bits in the last word are set to zero + std::fill_n(end(), __bits_per_word - end().__ctz_, 0); } template template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n) { ---------------- philnik777 wrote: I think I have basically the same question here: How does the `__copy` avoid the uninitialized read? https://github.com/llvm/llvm-project/pull/119632 From libcxx-commits at lists.llvm.org Sun Feb 2 10:36:27 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 10:36:27 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Simplify vector::__construct_at_end (Reopend) (PR #119632) In-Reply-To: Message-ID: <679fbb2b.170a0220.3101ee.29dd@mx.google.com> ================ @@ -552,36 +552,29 @@ vector::__recommend(size_type __new_size) const { } // Default constructs __n objects starting at __end_ -// Precondition: __n > 0 // Precondition: size() + __n <= capacity() // Postcondition: size() == size() + __n template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__construct_at_end(size_type __n, bool __x) { - size_type __old_size = this->__size_; + _LIBCPP_ASSERT_INTERNAL( + capacity() >= size() + __n, "vector::__construct_at_end called with insufficient capacity"); + std::fill_n(end(), __n, __x); this->__size_ += __n; - if (__old_size == 0 || ((__old_size - 1) / __bits_per_word) != ((this->__size_ - 1) / __bits_per_word)) { - if (this->__size_ <= __bits_per_word) - this->__begin_[0] = __storage_type(0); - else - this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0); - } - std::fill_n(__make_iter(__old_size), __n, __x); + if (end().__ctz_ != 0) // Ensure uninitialized leading bits in the last word are set to zero + std::fill_n(end(), __bits_per_word - end().__ctz_, 0); ---------------- philnik777 wrote: But how is the previous `fill_n` not reading uninitialized elements? It has to load the bits of the last word after all. https://github.com/llvm/llvm-project/pull/119632 From libcxx-commits at lists.llvm.org Sun Feb 2 10:47:11 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Sun, 02 Feb 2025 10:47:11 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] implement std::flat_set (PR #125241) In-Reply-To: Message-ID: <679fbdaf.170a0220.a8f41.5165@mx.google.com> https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/125241 >From f315d757119fde3cf298c18914a33e9cf76f27d1 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Fri, 31 Jan 2025 15:53:09 +0000 Subject: [PATCH 1/7] [libc++] implement std::flat_set --- libcxx/include/CMakeLists.txt | 2 + libcxx/include/__flat_set/flat_set.h | 853 ++++++++++++++++++ libcxx/include/flat_set | 59 ++ libcxx/include/module.modulemap | 11 + .../flat.set/flat.set.capacity/empty.pass.cpp | 48 + .../flat.set.capacity/empty.verify.cpp | 20 + .../flat.set.capacity/max_size.pass.cpp | 63 ++ .../flat.set/flat.set.capacity/size.pass.cpp | 66 ++ .../flat.set/flat.set.cons/alloc.pass.cpp | 60 ++ .../assign_initializer_list.pass.cpp | 56 ++ .../flat.set/flat.set.cons/compare.pass.cpp | 83 ++ .../flat.set.cons/containers.pass.cpp | 158 ++++ .../flat.set/flat.set.cons/copy.pass.cpp | 64 ++ .../flat.set.cons/copy_alloc.pass.cpp | 63 ++ .../copy_assign.addressof.compile.pass.cpp | 30 + .../flat.set.cons/copy_assign.pass.cpp | 85 ++ .../flat.set.cons/deduct.compile.pass.cpp | 49 + .../flat.set/flat.set.cons/deduct.pass.cpp | 341 +++++++ .../flat.set.cons/deduct_pmr.pass.cpp | 94 ++ .../flat.set/flat.set.cons/default.pass.cpp | 65 ++ .../flat.set.cons/default_noexcept.pass.cpp | 58 ++ .../flat.set.cons/dtor_noexcept.pass.cpp | 57 ++ .../flat.set.cons/initializer_list.pass.cpp | 151 ++++ .../flat.set/flat.set.cons/iter_iter.pass.cpp | 136 +++ .../flat.set/flat.set.cons/move.pass.cpp | 83 ++ .../flat.set.cons/move_alloc.pass.cpp | 75 ++ .../flat.set.cons/move_assign.pass.cpp | 69 ++ .../flat.set.cons/move_assign_clears.pass.cpp | 101 +++ .../move_assign_noexcept.pass.cpp | 85 ++ .../flat.set.cons/move_exceptions.pass.cpp | 58 ++ .../flat.set.cons/move_noexcept.pass.cpp | 94 ++ .../flat.set/flat.set.cons/pmr.pass.cpp | 322 +++++++ .../flat.set/flat.set.cons/range.pass.cpp | 173 ++++ .../flat.set.cons/sorted_container.pass.cpp | 143 +++ .../sorted_initializer_list.pass.cpp | 150 +++ .../flat.set.cons/sorted_iter_iter.pass.cpp | 156 ++++ .../flat.set.erasure/erase_if.pass.cpp | 89 ++ .../erase_if_exceptions.pass.cpp | 128 +++ .../flat.set.iterators/iterator.pass.cpp | 93 ++ .../iterator_comparison.pass.cpp | 154 ++++ ...rator_concept_conformance.compile.pass.cpp | 77 ++ ...range_concept_conformance.compile.pass.cpp | 52 ++ .../reverse_iterator.pass.cpp | 87 ++ .../flat.set.modifiers/clear.pass.cpp | 62 ++ .../flat.set.modifiers/emplace.pass.cpp | 141 +++ .../flat.set.modifiers/emplace_hint.pass.cpp | 154 ++++ .../flat.set.modifiers/erase_iter.pass.cpp | 121 +++ .../erase_iter_iter.pass.cpp | 91 ++ .../flat.set.modifiers/erase_key.pass.cpp | 91 ++ .../erase_key_transparent.pass.cpp | 142 +++ .../flat.set.modifiers/extract.pass.cpp | 83 ++ .../flat.set.modifiers/insert_cv.pass.cpp | 78 ++ .../insert_initializer_list.pass.cpp | 67 ++ .../insert_iter_cv.pass.cpp | 74 ++ .../insert_iter_iter.pass.cpp | 87 ++ .../insert_iter_rv.pass.cpp | 73 ++ .../flat.set.modifiers/insert_range.pass.cpp | 105 +++ .../flat.set.modifiers/insert_rv.pass.cpp | 80 ++ .../insert_sorted_initializer_list.pass.cpp | 58 ++ .../insert_sorted_iter_iter.pass.cpp | 77 ++ .../insert_transparent.pass.cpp | 169 ++++ .../flat.set.modifiers/replace.pass.cpp | 72 ++ .../swap_exception.pass.cpp | 61 ++ .../flat.set.modifiers/swap_free.pass.cpp | 94 ++ .../flat.set.modifiers/swap_member.pass.cpp | 92 ++ .../flat.set/flat.set.observers/comp.pass.cpp | 72 ++ .../flat.set.operations/contains.pass.cpp | 69 ++ .../contains_transparent.pass.cpp | 70 ++ .../flat.set.operations/count.pass.cpp | 69 ++ .../count_transparent.pass.cpp | 71 ++ .../flat.set.operations/equal_range.pass.cpp | 77 ++ .../equal_range_transparent.pass.cpp | 97 ++ .../flat.set.operations/find.pass.cpp | 53 ++ .../find_transparent.pass.cpp | 88 ++ .../flat.set.operations/lower_bound.pass.cpp | 70 ++ .../lower_bound_transparent.pass.cpp | 94 ++ .../flat.set.operations/upper_bound.pass.cpp | 71 ++ .../upper_bound_transparent.pass.cpp | 93 ++ .../container.adaptors/flat.set/helpers.h | 294 ++++++ .../flat.set/incomplete_type.pass.cpp | 33 + .../flat.set/op_compare.pass.cpp | 105 +++ .../flat.set/types.compile.pass.cpp | 94 ++ 82 files changed, 8453 insertions(+) create mode 100644 libcxx/include/__flat_set/flat_set.h create mode 100644 libcxx/include/flat_set create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/helpers.h create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8dac823503d73f5..75acf9f7899ff66 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -367,6 +367,7 @@ set(files __flat_map/sorted_equivalent.h __flat_map/sorted_unique.h __flat_map/utils.h + __flat_set/flat_set.h __format/buffer.h __format/concepts.h __format/container_adaptor.h @@ -986,6 +987,7 @@ set(files fenv.h filesystem flat_map + flat_set float.h format forward_list diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h new file mode 100644 index 000000000000000..c920632c453bf5e --- /dev/null +++ b/libcxx/include/__flat_set/flat_set.h @@ -0,0 +1,853 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FLAT_set_FLAT_SET_H +#define _LIBCPP___FLAT_set_FLAT_SET_H + +#include <__algorithm/lexicographical_compare_three_way.h> +#include <__algorithm/min.h> +#include <__algorithm/ranges_adjacent_find.h> +#include <__algorithm/ranges_equal.h> +#include <__algorithm/ranges_inplace_merge.h> +#include <__algorithm/ranges_lower_bound.h> +#include <__algorithm/ranges_partition_point.h> +#include <__algorithm/ranges_sort.h> +#include <__algorithm/ranges_unique.h> +#include <__algorithm/ranges_upper_bound.h> +#include <__algorithm/remove_if.h> +#include <__assert> +#include <__compare/synth_three_way.h> +#include <__concepts/swappable.h> +#include <__config> +#include <__cstddef/byte.h> +#include <__cstddef/ptrdiff_t.h> +#include <__flat_map/sorted_unique.h> +#include <__functional/invoke.h> +#include <__functional/is_transparent.h> +#include <__functional/operations.h> +#include <__fwd/vector.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/ranges_iterator_traits.h> +#include <__iterator/reverse_iterator.h> +#include <__memory/allocator_traits.h> +#include <__memory/uses_allocator.h> +#include <__memory/uses_allocator_construction.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/container_compatible_range.h> +#include <__ranges/drop_view.h> +#include <__ranges/from_range.h> +#include <__ranges/ref_view.h> +#include <__ranges/size.h> +#include <__ranges/subrange.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/container_traits.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_allocator.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_same.h> +#include <__utility/exception_guard.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include <__utility/scope_guard.h> +#include <__vector/vector.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template , class _KeyContainer = vector<_Key>> +class flat_set { + template + friend class flat_set; + + static_assert(is_same_v<_Key, typename _KeyContainer::value_type>); + static_assert(!is_same_v<_KeyContainer, std::vector>, "vector is not a sequence container"); + +public: + // types + using key_type = _Key; + using value_type = _Key; + using key_compare = __type_identity_t<_Compare>; + using value_compare = _Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename _KeyContainer::size_type; + using difference_type = typename _KeyContainer::difference_type; + using iterator = typename _KeyContainer::const_iterator; + using const_iterator = iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using container_type = _KeyContainer; + +private: + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = + uses_allocator::value; + + _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; + +public: + // [flat.set.cons], construct/copy/destroy + _LIBCPP_HIDE_FROM_ABI + flat_set() noexcept(is_nothrow_default_constructible_v<_KeyContainer> && is_nothrow_default_constructible_v<_Compare>) + : __keys_(), __compare_() {} + + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other) noexcept( + is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : __keys_(std::move(__other.__keys_)), __compare_(std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + // gcc does not like the `throw` keyword in a conditionally noexcept function + if constexpr (!(is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>)) { + throw; + } +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const key_compare& __comp) : __keys_(), __compare_(__comp) {} + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + __sort_and_unique(); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(), __compare_(__comp) { + insert(__first, __last); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(__first, __last), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg) + : flat_set(from_range, std::forward<_Range>(__rg), key_compare()) {} + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp) : flat_set(__comp) { + insert_range(std::forward<_Range>(__rg)); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(__il.begin(), __il.end(), __comp) {} + + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : flat_set(__ctor_uses_allocator_tag{}, __alloc, std::move(__other.__keys_), std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + throw; +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(sorted_unique, __first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, + _InputIterator __first, + _InputIterator __last, + const key_compare& __comp, + const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(sorted_unique, __first, __last); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert_range(std::forward<_Range>(__rg)); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert_range(std::forward<_Range>(__rg)); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(initializer_list __il) { + clear(); + insert(__il); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(flat_set&& __other) noexcept( + is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_Compare>) { + // No matter what happens, we always want to clear the other container before returning + // since we moved from it + auto __clear_other_guard = std::__make_scope_guard([&]() noexcept { __other.clear() /* noexcept */; }); + { + // If an exception is thrown, we have no choice but to clear *this to preserve invariants + auto __on_exception = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__other.__keys_); + __compare_ = std::move(__other.__compare_); + __on_exception.__complete(); + } + return *this; + } + + // iterators + _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + + _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return begin(); } + _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return end(); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + // [flat.set.capacity], capacity + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __keys_.empty(); } + + _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __keys_.size(); } + + _LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept { return __keys_.max_size(); } + + // [flat.set.modifiers], modifiers + template + _LIBCPP_HIDE_FROM_ABI pair emplace(_Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __try_emplace(std::forward<_Args>(__args)...); + } else { + return __try_emplace(_Key(std::forward<_Args>(__args)...)); + } + } + + template + _LIBCPP_HIDE_FROM_ABI iterator emplace_hint(const_iterator __hint, _Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __emplace_hint(std::move(__hint), std::forward<_Args>(__args)...); + } else { + return __emplace_hint(std::move(__hint), _Key(std::forward<_Args>(__args)...)); + } + } + + _LIBCPP_HIDE_FROM_ABI pair insert(const value_type& __x) { return emplace(__x); } + + _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { + return emplace(std::forward<_Kp>(__x)); + } + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, const value_type& __x) { + return emplace_hint(__hint, __x); + } + + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, value_type&& __x) { + return emplace_hint(__hint, std::move(__x)); + } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { + return emplace_hint(__hint, std::forward<_Kp>(__x)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, _InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { + if constexpr (ranges::sized_range<_Range>) { + __reserve(ranges::size(__range)); + } + + __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + } + + _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } + + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, initializer_list __il) { + insert(sorted_unique, __il.begin(), __il.end()); + } + + _LIBCPP_HIDE_FROM_ABI container_type extract() && { + auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; }); + auto __ret = std::move(__keys_); + return __ret; + } + + _LIBCPP_HIDE_FROM_ABI void replace(container_type&& __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys), "Either the key container is not sorted or it contains duplicates"); + auto __guard = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__keys); + __guard.__complete(); + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __position) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_iter = __keys_.erase(__position); + __on_failure.__complete(); + return __key_iter; + } + + // The following overload is the same as the iterator overload + // iterator erase(const_iterator __position); + + _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __x) { + auto __iter = find(__x); + if (__iter != end()) { + erase(__iter); + return 1; + } + return 0; + } + + template + requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + !is_convertible_v<_Kp &&, const_iterator>) + _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { + auto [__first, __last] = equal_range(__x); + auto __res = __last - __first; + erase(__first, __last); + return __res; + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_it = __keys_.erase(__first, __last); + __on_failure.__complete(); + return __key_it; + } + + _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __y) noexcept { + // warning: The spec has unconditional noexcept, which means that + // if any of the following functions throw an exception, + // std::terminate will be called. + // This is discussed in P2767, which hasn't been voted on yet. + ranges::swap(__compare_, __y.__compare_); + ranges::swap(__keys_, __y.__keys_); + } + + _LIBCPP_HIDE_FROM_ABI void clear() noexcept { __keys_.clear(); } + + // observers + _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __compare_; } + _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __compare_; } + + // set operations + _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __x) { return __find_impl(*this, __x); } + + _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { + return __find_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { + return __find_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { + return contains(__x) ? 1 : 0; + } + + _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { + return find(__x) != end(); + } + + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) { + return __equal_range_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) const { + return __equal_range_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { + return __equal_range_impl(*this, __x); + } + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { + return __equal_range_impl(*this, __x); + } + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const flat_set& __x, const flat_set& __y) { + return ranges::equal(__x, __y); + } + + friend _LIBCPP_HIDE_FROM_ABI auto operator<=>(const flat_set& __x, const flat_set& __y) { + return std::lexicographical_compare_three_way( + __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); + } + + friend _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __x, flat_set& __y) noexcept { __x.swap(__y); } + +private: + struct __ctor_uses_allocator_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_tag() = default; + }; + struct __ctor_uses_allocator_empty_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_empty_tag() = default; + }; + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), + __compare_(std::forward<_CompArg>(__comp)...) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc)), + __compare_(std::forward<_CompArg>(__comp)...) {} + + _LIBCPP_HIDE_FROM_ABI bool __is_sorted_and_unique(auto&& __key_container) const { + auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) { return !__compare_(__x, __y); }; + return ranges::adjacent_find(__key_container, __greater_or_equal_to) == ranges::end(__key_container); + } + + // This function is only used in constructors. So there is not exception handling in this function. + // If the function exits via an exception, there will be no flat_set object constructed, thus, there + // is no invariant state to preserve + _LIBCPP_HIDE_FROM_ABI void __sort_and_unique() { + ranges::sort(__keys_, __compare_); + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } else { + for (; __first != __last; ++__first) { + __keys_.insert(__keys_.end(), *__first); + } + } + if (size() != __old_size) { + if constexpr (!_WasSorted) { + ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); + } else { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__is_sorted_and_unique(__keys_ | ranges::views::drop(__old_size)), + "Either the key container is not sorted or it contains duplicates"); + } + ranges::inplace_merge(__keys_.begin(), __keys_.begin() + __old_size, __keys_.end(), __compare_); + + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + __on_failure.__complete(); + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __find_impl(_Self&& __self, const _Kp& __key) { + auto __it = __self.lower_bound(__key); + auto __last = __self.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return __last; + } + return __it; + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __equal_range_impl(_Self&& __self, const _Kp& __key) { + auto __it = ranges::lower_bound(__self.__keys_, __key, __self.__compare_); + auto __last = __self.__keys_.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return std::make_pair(__it, __it); + } + return std::make_pair(__it, std::next(__it)); + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_exact_pos(const_iterator __it, _KeyArg&& __key) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { + if constexpr (!__container_traits<_KeyContainer>::__emplacement_has_strong_exception_safety_guarantee) { + clear() /* noexcept */; + } + }); + auto __key_it = __keys_.emplace(__it, std::forward<_KeyArg>(__key)); + __on_failure.__complete(); + return __key_it; + } + + template + _LIBCPP_HIDE_FROM_ABI pair __try_emplace(_Kp&& __key) { + auto __it = lower_bound(__key); + if (__it == end() || __compare_(__key, *__it)) { + return pair(__emplace_exact_pos(__it, std::forward<_Kp>(__key)), true); + } else { + return pair(std::move(__it), false); + } + } + + template + _LIBCPP_HIDE_FROM_ABI bool __is_hint_correct(const_iterator __hint, _Kp&& __key) { + if (__hint != cbegin() && !__compare_(*(__hint - 1), __key)) { + return false; + } + if (__hint != cend() && __compare_(*__hint, __key)) { + return false; + } + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint(const_iterator __hint, _Kp&& __key) { + if (__is_hint_correct(__hint, __key)) { + if (__hint == cend() || __compare_(__key, *__hint)) { + return __emplace_exact_pos(__hint, std::forward<_Kp>(__key)); + } else { + // key equals + return __hint; + } + } else { + return __try_emplace(std::forward<_Kp>(__key)).first; + } + } + + _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __size) { + if constexpr (requires { __keys_.reserve(__size); }) { + __keys_.reserve(__size); + } + } + + template + friend typename flat_set<_Key2, _Compare2, _KeyContainer2>::size_type + erase_if(flat_set<_Key2, _Compare2, _KeyContainer2>&, _Predicate); + + _KeyContainer __keys_; + _LIBCPP_NO_UNIQUE_ADDRESS key_compare __compare_; + + struct __key_equiv { + _LIBCPP_HIDE_FROM_ABI __key_equiv(key_compare __c) : __comp_(__c) {} + _LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const { + return !__comp_(__x, __y) && !__comp_(__y, __x); + } + key_compare __comp_; + }; +}; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(_KeyContainer, _Compare = _Compare()) -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(_KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(_KeyContainer, _Compare, _Allocator) -> flat_set; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare = _Compare()) + -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(sorted_unique_t, _KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare, _Allocator) + -> flat_set; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(_InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >, + class _Allocator = allocator, + class = __enable_if_t::value && __is_allocator<_Allocator>::value>> +flat_set(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> flat_set< + ranges::range_value_t<_Range>, + _Compare, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template ::value>> +flat_set(from_range_t, _Range&&, _Allocator) -> flat_set< + ranges::range_value_t<_Range>, + less>, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template +struct uses_allocator, _Allocator> + : bool_constant> {}; + + template + _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type + erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; + } + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FLAT_set_FLAT_SET_H diff --git a/libcxx/include/flat_set b/libcxx/include/flat_set new file mode 100644 index 000000000000000..d03645fafafdba0 --- /dev/null +++ b/libcxx/include/flat_set @@ -0,0 +1,59 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_FLAT_SET +#define _LIBCPP_FLAT_SET + +/* + Header synopsis + +#include // see [compare.syn] +#include // see [initializer.list.syn] + +namespace std { + // [flat.set], class template flat_set + template, class KeyContainer = vector> + class flat_set; + + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + + template + struct uses_allocator, Allocator>; + + // [flat.set.erasure], erasure for flat_set + template + typename flat_set::size_type + erase_if(flat_set& c, Predicate pred); +} +*/ + +#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +# include <__cxx03/__config> +#else +# include <__config> + +# if _LIBCPP_STD_VER >= 23 +# include <__flat_map/sorted_unique.h> +# include <__flat_set/flat_set.h> +# endif + +// for feature-test macros +# include + +// standard required includes +# include +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif +#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) + +#endif // _LIBCPP_FLAT_SET diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4bae02137b37b21..abc351d5923963d 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1263,6 +1263,17 @@ module std [system] { export * } + module flat_set { + module flat_set { + header "__flat_set/flat_set.h" + export std.vector.vector + export std.vector.fwd + } + + header "flat_set" + export * + } + module format { module buffer { header "__format/buffer.h" diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp new file mode 100644 index 000000000000000..204df1d681af1bc --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m; + ASSERT_SAME_TYPE(decltype(m.empty()), bool); + ASSERT_NOEXCEPT(m.empty()); + assert(m.empty()); + assert(std::as_const(m).empty()); + m = {1}; + assert(!m.empty()); + m.clear(); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp new file mode 100644 index 000000000000000..161fe533eabacb0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include + +void f() { + std::flat_set c; + c.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp new file mode 100644 index 000000000000000..cd7f424e00ece23 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type max_size() const noexcept; + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_allocator.h" +#include "test_macros.h" + +int main(int, char**) { + { + using A1 = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= 10); + LIBCPP_ASSERT(c.max_size() == 10); + } + { + using A = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + LIBCPP_ASSERT(c.max_size() == max_dist); + } + { + typedef std::flat_set C; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + assert(c.max_size() <= alloc_max_size(std::allocator())); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp new file mode 100644 index 000000000000000..7c156e95ecb1c86 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type size() const noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using M = std::flat_set, KeyContainer>; + using S = typename M::size_type; + { + const M m = {1, 1, 4, 5, 5}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 3); + } + { + const M m = {1}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 1); + } + { + const M m; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 0); + } + { + M m; + S s = 1000000; + for (auto i = 0u; i < s; ++i) { + m.emplace(i); + } + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == s); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp new file mode 100644 index 000000000000000..acc0817d7cac4d6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// explicit flat_set(const Allocator& a); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // explicit + using M = std::flat_set, std::vector>>; + + static_assert(std::is_constructible_v>); + static_assert(!std::is_convertible_v, M>); + } + { + using A = test_allocator; + using M = std::flat_set, std::vector>>; + M m(A(0, 5)); + assert(m.empty()); + assert(m.begin() == m.end()); + auto v = std::move(m).extract(); + assert(v.get_allocator().get_id() == 5); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp new file mode 100644 index 000000000000000..7f75f1e1611e3b4 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(initializer_list il); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m = {8, 10}; + assert(m.size() == 2); + m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + int expected[] = {1, 2, 3, 4, 5, 6}; + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + } + { + M m = {10, 8}; + assert(m.size() == 2); + m = {3}; + int expected[] = {3}; + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp new file mode 100644 index 000000000000000..b3bee18f5a936b1 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(const key_compare& comp); +// template +// flat_set(const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + auto m = std::flat_set(C(3)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(3)); + } + { + // The one-argument ctor is explicit. + using C = test_less; + static_assert(std::is_constructible_v, C>); + static_assert(!std::is_convertible_v>); + + static_assert(std::is_constructible_v, std::less>); + static_assert(!std::is_convertible_v, std::flat_set>); + } + { + using C = test_less; + using A1 = test_allocator; + auto m = std::flat_set>(C(4), A1(5)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + { + // explicit(false) + using C = test_less; + using A1 = test_allocator; + std::flat_set> m = {C(4), A1(5)}; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp new file mode 100644 index 000000000000000..3d1e6240c952e8c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -0,0 +1,158 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(container_type key_cont, const key_compare& comp = key_compare()); +// template +// flat_set(const container_type& key_cont, const Allocator& a); +// template +// flat_set(const container_type& key_cont, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(container_type) + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + + // explicit + static_assert(std::is_constructible_v&>); + static_assert(!ImplicitlyConstructible&>); + } + { + // flat_set(container_type) + // move-only + MoveOnly expected[] = {3, 2, 1}; + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks; + ks.push_back(1); + ks.push_back(3); + ks.push_back(2); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(container_type) + // container's allocator is used + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(5)); + } + { + // flat_set(container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + + // explicit + static_assert(std::is_constructible_v&, const C&>); + static_assert(!ImplicitlyConstructible&, const C&>); + } + { + // flat_set(container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(ks, A(4)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , const Allocator&) + // explicit(false) + using A = test_allocator; + using M = std::flat_set, std::deque>; + static_assert(ImplicitlyConstructible&, const A&>); + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + M m = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4), A(5)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + auto m_copy = m; + auto keys = std::move(m_copy).extract(); + assert(keys.get_allocator() == A(5)); + + // explicit(false) + static_assert(ImplicitlyConstructible&, const A&>); + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + keys = std::move(m2).extract(); + assert(keys.get_allocator() == A(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp new file mode 100644 index 000000000000000..f1dbc955e1b0de7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(-2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp new file mode 100644 index 000000000000000..59fb9d0a38366fe --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M(mo, test_allocator(3)); + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(3)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp new file mode 100644 index 000000000000000..169b469f3bca68b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& s); + +// Validate whether the container can be copy-assigned (move-assigned, swapped) +// with an ADL-hijacking operator& + +#include +#include + +#include "test_macros.h" +#include "operator_hijacker.h" + +void test() { + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp new file mode 100644 index 000000000000000..cdd5045f4bb9f7e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // test_allocator is not propagated + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M({{3, 4, 5}}, C(3), test_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + // other_allocator is propagated + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = M({3, 4, 5}, C(3), other_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + { + // comparator is copied and invariant is preserved + using M = std::flat_set>; + M mo = M({1, 2}, std::less()); + M m = M({1, 2}, std::greater()); + assert(m.key_comp()(2, 1) == true); + assert(m != mo); + m = mo; + assert(m.key_comp()(2, 1) == false); + assert(m == mo); + } + { + // self-assignment + using M = std::flat_set; + M m = {{1, 2}}; + m = static_cast(m); + assert((m == M{{1, 2}})); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp new file mode 100644 index 000000000000000..5db8c4ca7224665 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Test CTAD on cases where deduction should fail. + +#include +#include +#include +#include +#include + +struct NotAnAllocator { + friend bool operator<(NotAnAllocator, NotAnAllocator) { return false; } +}; + +template +concept CanDeductFlatSet = requires { std::flat_set{std::declval()...}; }; + +static_assert(CanDeductFlatSet, std::vector>); + +// cannot deduce Key and T from nothing +static_assert(!CanDeductFlatSet<>); + +// cannot deduce Key and T from just (KeyContainer), even if it's a container of pairs +static_assert(!CanDeductFlatSet>>); + +// cannot deduce Key and T from just (KeyContainer, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>>); + +// cannot deduce Key and T from just (Compare) +static_assert(!CanDeductFlatSet>); + +// cannot deduce Key and T from just (Compare, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>); + +// cannot deduce Key and T from just (Allocator) +static_assert(!CanDeductFlatSet>); + +// cannot convert from some arbitrary unrelated type +static_assert(!CanDeductFlatSet); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp new file mode 100644 index 000000000000000..612e64a7c42f23e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -0,0 +1,341 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "deduction_guides_sfinae_checks.h" +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_copy() { + { + std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set s(source); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s{source}; // braces instead of parens + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s(source, std::allocator()); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } +} + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(ks, vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(ks, vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_iter_iter() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m(std::begin(arr), std::end(arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) + static_assert(std::is_same_v>); + assert(s.size() == 3); + } +} + +void test_iter_iter_compare() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m(std::begin(arr), std::end(arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } +} + +void test_initializer_list() { + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } + { + using M = std::flat_set; + M m; + std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + assert(s[m] == m); + } +} + +void test_initializer_list_compare() { + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } +} + +void test_from_range() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(std::from_range, r); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +void test_from_range_compare() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(std::from_range, r, std::greater()); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +int main(int, char**) { + // Each test function also tests the sorted_unique-prefixed and allocator-suffixed overloads. + test_copy(); + test_containers(); + test_containers_compare(); + test_iter_iter(); + test_iter_iter_compare(); + test_initializer_list(); + test_initializer_list_compare(); + test_from_range(); + test_from_range_compare(); + + AssociativeContainerDeductionGuidesSfinaeAway>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp new file mode 100644 index 000000000000000..df8d6d885ee5246 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + const int expected[] = {1, 2, 3, INT_MAX}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + const int expected[] = {INT_MAX, 3, 2, 1}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +int main(int, char**) { + test_containers(); + test_containers_compare(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp new file mode 100644 index 000000000000000..64b0bfcb383a720 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + std::flat_set m; + assert(m.empty()); + } + { + // explicit(false) + std::flat_set m = {}; + assert(m.empty()); + } + { + std::flat_set>> m; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp().default_constructed_); + } + { + using A1 = explicit_allocator; + using A2 = explicit_allocator; + { + std::flat_set> m; + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + { + A1 a1; + std::flat_set> m(a1); + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp new file mode 100644 index 000000000000000..b4a3b6de205a31b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set() +// noexcept( +// is_nothrow_default_constructible_v && +// is_nothrow_default_constructible_v); + +// This tests a conforming extension + +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +int main(int, char**) { +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp new file mode 100644 index 000000000000000..c0d315c0ce74b4b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// ~flat_set(); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingDtorComp { + bool operator()(const auto&, const auto&) const; + ~ThrowingDtorComp() noexcept(false) {} +}; + +int main(int, char**) { + { + using C = std::flat_set; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::vector>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::deque>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(!std::is_nothrow_destructible_v); + C c; + } +#endif // _LIBCPP_VERSION + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp new file mode 100644 index 000000000000000..cd2319e91f760d9 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -0,0 +1,151 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(initializer_list il, const key_compare& comp = key_compare()); +// template +// flat_set(initializer_list il, const Alloc& a); +// template +// flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +#include "../../../test_compare.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + } + + int expected[] = {1, 2, 3, 5}; + { + // flat_set(initializer_list); + using M = std::flat_set; + std::initializer_list il = {5, 2, 2, 3, 1, 3}; + M m(il); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + // explicit(false) + using M = std::flat_set; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + using M = std::flat_set, std::deque>>; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + { + using A = explicit_allocator; + { + // flat_set(initializer_list); + // different comparator + using M = std::flat_set>; + M m = {1, 2, 3}; + assert(m.size() == 1); + LIBCPP_ASSERT(*m.begin() == 1); + assert(m.key_comp().default_constructed_); + } + { + // flat_set(initializer_list, const Allocator&); + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + } + { + // flat_set(initializer_list, const key_compare&); + using C = test_less; + using M = std::flat_set; + auto m = M({5, 2, 2, 3, 1, 3}, C(10)); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + assert(m.key_comp() == C(10)); + + // explicit(false) + M m2 = {{5, 2, 2, 1, 3, 3}, C(10)}; + assert(m2 == m); + assert(m2.key_comp() == C(10)); + } + { + // flat_set(initializer_list, const key_compare&); + // Sorting uses the comparator that was passed in + using M = std::flat_set, std::deque>>; + auto m = M({5, 2, 2, 1, 3, 1}, std::greater()); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + assert(m.key_comp()(2, 1) == true); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using A = explicit_allocator; + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, {}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp new file mode 100644 index 000000000000000..65eebc21a66c4cb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(InputIterator first, InputIterator last, const Allocator& a); +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(InputIterator , InputIterator) + // cpp17_input_iterator + using M = std::flat_set; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)}; + assert(m2 == m); + } + { + // flat_set(InputIterator , InputIterator) + // greater + using M = std::flat_set, std::deque>>; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(InputIterator , InputIterator) + // Test when the operands are of array type (also contiguous iterator type) + using M = std::flat_set, std::vector>>; + auto m = M(ar, ar); + assert(m.empty()); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&) + using C = test_less; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {ar, ar + 9, C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + auto m = M(ar, ar + 9, A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + M m = {ar, ar + 9, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {ar, ar + 9, {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp new file mode 100644 index 000000000000000..69b340ad09fe158 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A(7)); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A(7)); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().get_id() == test_alloc_base::moved_value); + } + { + using C = test_less; + using A = min_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A()); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A()); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A()); + } + { + // A moved-from flat_set maintains its class invariant in the presence of moved-from comparators. + using M = std::flat_set>; + M mo = M({1, 2, 3}, std::less()); + M m = std::move(mo); + assert(m.size() == 3); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.key_comp()(1, 2) == true); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + LIBCPP_ASSERT(m.key_comp()(1, 2) == true); + LIBCPP_ASSERT(mo.empty()); + mo.insert({1, 2, 3}); // insert has no preconditions + assert(m == mo); + } + { + // moved-from object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m1.size() == 0); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp new file mode 100644 index 000000000000000..fc7f68d8c967ad2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + int expected[] = {1, 2, 3}; + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + auto mo = M(expected, expected + 3, C(5), A(7)); + auto m = M(std::move(mo), A(3)); + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(3)); + assert(std::ranges::equal(keys, expected )); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A(7)); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2(std::move(m1), std::allocator{}); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp new file mode 100644 index 000000000000000..b16dc38dd402859 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{4, 5})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + m = std::move(mo); + assert((m == M{5, 4, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A()); + assert(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp new file mode 100644 index 000000000000000..50817f4be8a8125 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); +// Preserves the class invariant for the moved-from flat_set. + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +int main(int, char**) { + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp new file mode 100644 index 000000000000000..86f3568f0d67a6b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&& c) +// noexcept( +// is_nothrow_move_assignable::value && +// is_nothrow_move_assignable::value && +// is_nothrow_copy_assignable::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_macros.h" + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp new file mode 100644 index 000000000000000..17e4e40387606ce --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// flat_set(flat_set&& s); +// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +int main(int, char**) { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp new file mode 100644 index 000000000000000..49d1151fd8a993c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&) +// noexcept(is_nothrow_move_constructible::value && +// is_nothrow_move_constructible::value && +// is_nothrow_copy_constructible::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp new file mode 100644 index 000000000000000..785718d2eed333f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -0,0 +1,322 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +// Test various constructors with pmr + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // flat_set(const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::polymorphic_allocator pa = &mr; + auto m1 = M(pa); + assert(m1.empty()); + assert(std::move(m1).extract().get_allocator() == pa); + auto m2 = M(&mr); + assert(m2.empty()); + assert(std::move(m2).extract().get_allocator() == pa); + } + { + // flat_set(const key_compare& comp, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::greater()); + assert(vm[0] == M{}); + assert(vm[0].key_comp()(2, 1) == true); + assert(vm[0].value_comp()(2, 1) == true); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + // const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + assert(ks.get_allocator().resource() != &mr); + vm.emplace_back(ks); + assert(ks.size() == 9); // ks' value is unchanged, since it was an lvalue above + assert((vm[0] == M{1, 2, 3})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const flat_set&, const allocator_type&); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, C(5), &mr1); + M m = {mo, &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + auto keys = std::move(m).extract(); + assert((keys == std::pmr::vector{1, 2, 3})); + assert(keys.get_allocator().resource() == &mr2); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + auto keys2 = std::move(mo).extract(); + assert((keys2 == std::pmr::vector{1, 2, 3})); + assert(keys2.get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set&, const allocator_type&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::vector vs; + M m = {1, 2, 3}; + vs.push_back(m); + assert(vs[0] == m); + } + { + // flat_set& operator=(const flat_set& m); + // pmr allocator is not propagated + using M = std::flat_set, std::pmr::deque>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, &mr1); + M m = M({4, 5}, &mr2); + m = mo; + assert((m == M{1, 2, 3})); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // mo is unchanged + assert((mo == M{1, 2, 3})); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set& m); + using C = test_less; + std::pmr::monotonic_buffer_resource mr; + using M = std::flat_set>; + auto mo = M({1, 2, 3}, C(5), &mr); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert((m == M{1, 2, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator().resource() == std::pmr::get_default_resource()); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert((mo == M{1, 2, 3})); + auto kso = std::move(mo).extract(); + assert(kso.get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il, C(5)); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + assert(vm[0].key_comp() == C(5)); + } + { + // flat_set(InputIterator first, InputIterator last, const Allocator& a); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // cpp17 iterator + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(ar, ar); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(flat_set&&, const allocator_type&); + int expected[] = {1, 2, 3}; + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 3, 1, 2}, C(5), &mr1); + M m = {std::move(mo), &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + assert(std::equal(m.begin(), m.end(), expected, expected + 3)); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(flat_set&&, const allocator_type&); + using M = std::flat_set, std::pmr::deque>; + std::pmr::vector vs; + M m = {1, 3, 1, 2}; + vs.push_back(std::move(m)); + assert((std::move(vs[0]).extract() == std::pmr::deque{1, 2, 3})); + } + { + // flat_set& operator=(flat_set&&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = + M({"short", "very long string that definitely won't fit in the SSO buffer and therefore becomes empty on move"}, + &mr1); + M m = M({"don't care"}, &mr2); + m = std::move(mo); + assert(m.size() == 2); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.begin()->get_allocator().resource() == &mr2); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + mo.insert("foo"); + assert(mo.begin()->get_allocator().resource() == &mr1); + } + { + // flat_set(from_range_t, R&&, const Alloc&); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // input_range + using M = std::flat_set, std::pmr::vector>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(ar, ar)); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 2, 4, 10}; + vm.emplace_back(std::sorted_unique, ks); + assert(!ks.empty()); // it was an lvalue above + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, const container_type& key_cont,const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks({1, 2, 4, 10}, &mr); + vm.emplace_back(std::sorted_unique, ks); + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp new file mode 100644 index 000000000000000..bb9f99c228bfecc --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -0,0 +1,173 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// flat_set(from_range_t, R&&) +// template R> +// flat_set(from_range_t, R&&, const key_compare&) +// template R, class Alloc> +// flat_set(from_range_t, R&&, const Alloc&); +// template R, class Alloc> +// flat_set(from_range_t, R&&, const key_compare&, const Alloc&); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +// test constraint container-compatible-range + +template +using RangeOf = std::ranges::subrange; +using Set = std::flat_set; + +static_assert(std::is_constructible_v>); +static_assert(std::is_constructible_v>); +static_assert(!std::is_constructible_v>>); + +static_assert(std::is_constructible_v, std::less>); +static_assert(std::is_constructible_v, std::less>); +static_assert(!std::is_constructible_v>, std::less>); + +static_assert(std::is_constructible_v, std::allocator>); +static_assert(std::is_constructible_v, std::allocator>); +static_assert(!std::is_constructible_v>, std::allocator>); + +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert( + !std:: + is_constructible_v>, std::less, std::allocator>); + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(from_range_t, R&&) + // input_range && !common + using M = std::flat_set; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))}; + assert(m2 == m); + } + { + // flat_set(from_range_t, R&&) + // greater + using M = std::flat_set, std::deque>>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(from_range_t, R&&) + // contiguous range + using M = std::flat_set; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9)); + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(from_range_t, R&&, const key_compare&) + using C = test_less; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {std::from_range, R(ar, ar + 9), C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp new file mode 100644 index 000000000000000..2d442d49667bd07 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(sorted_unique_t, container_type key_cont, const key_compare& comp = key_compare()); +// +// template +// flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); +// template +// flat_set(sorted_unique_t, const container_type& key_cont, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, container_type) + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + auto ks2 = ks; + + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + + // explicit(false) + M m2 = {std::sorted_unique, std::move(ks2)}; + assert(m == m2); + } + { + // flat_set(sorted_unique_t, container_type) + // non-default container, comparator and allocator type + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks = {10, 4, 2, 1}; + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + } + { + // flat_set(sorted_unique_t, container_type) + // allocator copied into the containers + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + assert(std::move(m).extract().get_allocator() == A(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + + auto m = M(std::sorted_unique, ks, C(4)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, C(4)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 2, 4, 10}; + auto m = M(std::sorted_unique, ks, C(4), A(5)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + assert(M(m).extract().get_allocator() == A(5)); + + // explicit(false) + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + assert(std::move(m2).extract().get_allocator() == A(5)); + } + { + // flat_set(sorted_unique_t, container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, ks, A(6)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 4, 10})); + assert(M(m).extract().get_allocator() == A(6)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, A(6)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp new file mode 100644 index 000000000000000..01956a78c7f48dd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t s, initializer_list il, +// const key_compare& comp = key_compare()) +// template +// flat_set(sorted_unique_t, initializer_list il, const Alloc& a); +// template +// flat_set(sorted_unique_t, initializer_list il, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +std::initializer_list il = {1, 2, 4, 5}; + +const auto il1 = il; +const auto il2 = il; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + } + + { + // flat_set(sorted_unique_t, initializer_list); + using M = std::flat_set; + auto m = M(std::sorted_unique, il1); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, il1}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + using M = std::flat_set>; + auto m = M(std::sorted_unique, il1, std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, il1, std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + std::initializer_list il4{5, 4, 2, 1}; + auto m = M(std::sorted_unique, il4, std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, initializer_list, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + auto m = M(std::sorted_unique, il2, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, il2, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(std::sorted_unique, il2, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {std::sorted_unique, il2, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp new file mode 100644 index 000000000000000..b5229a84dd51333 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // cpp17_input_iterator + using M = std::flat_set; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // cpp_17_input_iterator + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + int ar[] = {5, 4, 2, 1}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[1] = {42}; + auto m = M(std::sorted_unique, ar, ar, C(5)); + assert(m.empty()); + assert(m.key_comp() == C(5)); + } + { + // flat_set(sorted_unique_t, InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, ar, ar + 4, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + int ar[] = {1, 2, 4, 5}; + M m = {std::sorted_unique, ar, ar + 4, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp new file mode 100644 index 000000000000000..134db83aef3cad2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "min_allocator.h" + +// Verify that `flat_set` (like `set`) does NOT support std::erase. +// +template +concept HasStdErase = requires(S& s, typename S::value_type x) { std::erase(s, x); }; +static_assert(HasStdErase>); +static_assert(!HasStdErase>); + +template +M make(std::initializer_list vals) { + M ret; + for (int v : vals) + ret.emplace(v); + return ret; +} + +template +void test0( + std::initializer_list vals, Pred p, std::initializer_list expected, std::size_t expected_erased_count) { + M s = make(vals); + ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p))); + assert(expected_erased_count == std::erase_if(s, p)); + assert(s == make(expected)); +} + +template +void test() { + // Test all the plausible signatures for this predicate. + auto is1 = [](typename S::const_reference v) { return v == 1; }; + auto is2 = [](typename S::value_type v) { return v == 2; }; + auto is3 = [](const typename S::value_type& v) { return v == 3; }; + auto is4 = [](auto v) { return v == 4; }; + auto True = [](const auto&) { return true; }; + auto False = [](auto&&) { return false; }; + + test0({}, is1, {}, 0); + + test0({1}, is1, {}, 1); + test0({1}, is2, {1}, 0); + + test0({1, 2}, is1, {2}, 1); + test0({1, 2}, is2, {1}, 1); + test0({1, 2}, is3, {1, 2}, 0); + + test0({1, 2, 3}, is1, {2, 3}, 1); + test0({1, 2, 3}, is2, {1, 3}, 1); + test0({1, 2, 3}, is3, {1, 2}, 1); + test0({1, 2, 3}, is4, {1, 2, 3}, 0); + + test0({1, 2, 3}, True, {}, 3); + test0({1, 2, 3}, False, {1, 2, 3}, 0); +} + +int main(int, char**) { + test>(); + test, std::vector>>>(); + test, std::vector>>>(); + test, std::deque>>>(); + test, std::deque>>>(); + test>(); + test>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp new file mode 100644 index 000000000000000..6bbe1ad4f016705 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -0,0 +1,128 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); +// If any member function in [flat.set.defn] exits via an exception, the invariant is restored. +// (This is not a member function, but let's respect the invariant anyway.) + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct Counter { + int c1, c2, throws; + void tick() { + c1 -= 1; + if (c1 == 0) { + c1 = c2; + throws += 1; + throw 42; + } + } +}; +Counter g_counter = {0, 0, 0}; + +struct ThrowingAssignment { + ThrowingAssignment(int i) : i_(i) {} + ThrowingAssignment(const ThrowingAssignment&) = default; + ThrowingAssignment& operator=(const ThrowingAssignment& rhs) { + g_counter.tick(); + i_ = rhs.i_; + g_counter.tick(); + return *this; + } + operator int() const { return i_; } + int i_; +}; + +struct ThrowingComparator { + bool operator()(const ThrowingAssignment& a, const ThrowingAssignment& b) const { + g_counter.tick(); + return a.i_ < b.i_; + } +}; + +struct ErasurePredicate { + bool operator()(const auto& x) const { return (3 <= x && x <= 5); } +}; + +int main(int, char**) { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + { + using M = std::flat_set; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + M m = M({1, 2, 3, 4, 5, 6, 7, 8}); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + + { + using M = std::flat_set>; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + std::deque container = {5, 6, 7, 8}; + container.insert(container.begin(), {1, 2, 3, 4}); + M m = M(std::move(container)); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp new file mode 100644 index 000000000000000..c07297a141ad109 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator begin() noexcept; +// const_iterator begin() const noexcept +// iterator end() noexcept; +// const_iterator end() const noexcept; +// +// const_iterator cbegin() const noexcept; +// const_iterator cend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.begin()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cbegin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.begin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(m.end()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cend()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.end()), typename M::const_iterator); + static_assert(noexcept(m.begin())); + static_assert(noexcept(cm.begin())); + static_assert(noexcept(m.cbegin())); + static_assert(noexcept(m.end())); + static_assert(noexcept(cm.end())); + static_assert(noexcept(m.cend())); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(std::distance(cm.begin(), cm.end()) == 4); + assert(std::distance(m.cbegin(), m.cend()) == 4); + typename M::iterator i; // default-construct + i = m.begin(); // move-assignment + typename M::const_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 1; j <= 4; ++j, ++i) { // pre-increment + assert(*i == j); // operator* + } + assert(i == m.end()); + for (int j = 4; j >= 1; --j) { + --i; // pre-decrement + assert((*i) == j); + } + assert(i == m.begin()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // N3644 testing + using C = std::flat_set; + C::iterator ii1{}, ii2{}; + C::iterator ii4 = ii1; + C::const_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp new file mode 100644 index 000000000000000..29441dcc57d40e4 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set iterators should be C++20 random access iterators + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using KI = typename KeyContainer::iterator; + using I = M::iterator; + using CI = M::const_iterator; + using RI = M::reverse_iterator; + using CRI = M::const_reverse_iterator; + + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + + M m = {1, 2, 3, 4}; + + I i1 = m.begin(); + I i2 = m.begin() + 1; + + assert(i1 == i1); + assert(!(i1 != i1)); + assert(i1 != i2); + assert(!(i1 == i2)); + assert(i1 < i2); + assert(!(i1 < i1)); + assert(i1 <= i1); + assert(i1 <= i2); + assert(!(i2 <= i1)); + assert(i2 > i1); + assert(!(i2 > i2)); + assert(i2 >= i1); + assert(i2 >= i2); + assert(!(i1 >= i2)); + + CI ci1 = m.cbegin(); + CI ci2 = m.cbegin() + 1; + assert(ci1 == ci1); + assert(!(ci1 != ci1)); + assert(ci1 != ci2); + assert(!(ci1 == ci2)); + assert(ci1 < ci2); + assert(!(ci1 < ci1)); + assert(ci1 <= ci1); + assert(ci1 <= ci2); + assert(!(ci2 <= ci1)); + assert(ci2 > ci1); + assert(!(ci2 > ci2)); + assert(ci2 >= ci1); + assert(ci2 >= ci2); + assert(!(ci1 >= ci2)); + + RI ri1 = m.rbegin(); + RI ri2 = m.rbegin() + 1; + assert(ri1 == ri1); + assert(!(ri1 != ri1)); + assert(ri1 != ri2); + assert(!(ri1 == ri2)); + assert(ri1 < ri2); + assert(!(ri1 < ri1)); + assert(ri1 <= ri1); + assert(ri1 <= ri2); + assert(!(ri2 <= ri1)); + assert(ri2 > ri1); + assert(!(ri2 > ri2)); + assert(ri2 >= ri1); + assert(ri2 >= ri2); + assert(!(ri1 >= ri2)); + + CRI cri1 = m.crbegin(); + CRI cri2 = m.crbegin() + 1; + assert(cri1 == cri1); + assert(!(cri1 != cri1)); + assert(cri1 != cri2); + assert(!(cri1 == cri2)); + assert(cri1 < cri2); + assert(!(cri1 < cri1)); + assert(cri1 <= cri1); + assert(cri1 <= cri2); + assert(!(cri2 <= cri1)); + assert(cri2 > cri1); + assert(!(cri2 > cri2)); + assert(cri2 >= cri1); + assert(cri2 >= cri2); + assert(!(cri1 >= cri2)); + + if constexpr (std::three_way_comparable) { + static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::same_as I()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as RI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + + assert(i1 <=> i1 == std::strong_ordering::equivalent); + assert(i1 <=> i2 == std::strong_ordering::less); + assert(i2 <=> i1 == std::strong_ordering::greater); + + assert(ci1 <=> ci1 == std::strong_ordering::equivalent); + assert(ci1 <=> ci2 == std::strong_ordering::less); + assert(ci2 <=> ci1 == std::strong_ordering::greater); + + assert(ri1 <=> ri1 == std::strong_ordering::equivalent); + assert(ri1 <=> ri2 == std::strong_ordering::less); + assert(ri2 <=> ri1 == std::strong_ordering::greater); + + assert(cri1 <=> cri1 == std::strong_ordering::equivalent); + assert(cri1 <=> cri2 == std::strong_ordering::less); + assert(cri2 <=> cri1 == std::strong_ordering::greater); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp new file mode 100644 index 000000000000000..35b45b6e797233e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator, const_iterator, reverse_iterator, const_reverse_iterator + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + using I = C::iterator; + using CI = C::const_iterator; + using RI = C::reverse_iterator; + using CRI = C::const_reverse_iterator; + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp new file mode 100644 index 000000000000000..4ec64e706b70218 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include +#include +#include +#include +#include +#include "MinSequenceContainer.h" +#include "min_allocator.h" + +template +void test() { + { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + + static_assert(std::same_as, typename C::iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(std::ranges::viewable_range); + + static_assert(std::same_as, typename C::const_iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(!std::ranges::viewable_range); + } +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp new file mode 100644 index 000000000000000..a16383cdcf53830 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// reverse_iterator rbegin() noexcept; +// const_reverse_iterator rbegin() const noexcept; +// reverse_iterator rend() noexcept; +// const_reverse_iterator rend() const noexcept; +// +// const_reverse_iterator crbegin() const noexcept; +// const_reverse_iterator crend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include + +#include "test_macros.h" +#include + +int main(int, char**) { + { + using M = std::flat_set, std::deque>; + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.rbegin()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.rend()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crend()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rend()), M::const_reverse_iterator); + static_assert(noexcept(m.rbegin())); + static_assert(noexcept(cm.rbegin())); + static_assert(noexcept(m.crbegin())); + static_assert(noexcept(m.rend())); + static_assert(noexcept(cm.rend())); + static_assert(noexcept(m.crend())); + assert(m.size() == 4); + assert(std::distance(m.rbegin(), m.rend()) == 4); + assert(std::distance(cm.rbegin(), cm.rend()) == 4); + assert(std::distance(m.crbegin(), m.crend()) == 4); + assert(std::distance(cm.crbegin(), cm.crend()) == 4); + M::reverse_iterator i; // default-construct + ASSERT_SAME_TYPE(decltype(*i), const int&); + i = m.rbegin(); // move-assignment + M::const_reverse_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 4; j >= 1; --j, ++i) { // pre-increment + assert(*i == j); + } + assert(i == m.rend()); + for (int j = 1; j <= 4; ++j) { + --i; // pre-decrement + assert(*i == j); + } + assert(i == m.rbegin()); + } + { + // N3644 testing + using C = std::flat_set; + C::reverse_iterator ii1{}, ii2{}; + C::reverse_iterator ii4 = ii1; + C::const_reverse_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp new file mode 100644 index 000000000000000..221a13fa057577a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// void clear() noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// test noexcept + +template +concept NoExceptClear = requires(T t) { + { t.clear() } noexcept; +}; + +static_assert(NoExceptClear>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptClear, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4, 5}; + assert(m.size() == 5); + ASSERT_NOEXCEPT(m.clear()); + ASSERT_SAME_TYPE(decltype(m.clear()), void); + m.clear(); + assert(m.size() == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp new file mode 100644 index 000000000000000..95f7a3c5f5d34a2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -0,0 +1,141 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// pair emplace(Args&&... args); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the begin + M m = {3, 5, 6, 7}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted in the middle + M m = {0, 1, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the end + M m = {0, 1}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } + { + // key already exists and original at the begin + M m = {2, 3, 5, 6}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original in the middle + M m = {0, 2, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 1); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original at the end + M m = {0, 1, 2}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace()), R); + R r = m.emplace(2, 0.0); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace(1, 3.5); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace(1, 3.5); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp new file mode 100644 index 000000000000000..de855d5e5c30097 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// iterator emplace_hint(const_iterator position, Args&&... args); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace_hint(m.end(), typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + } + { + // hints correct at the begin + M m = {3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints correct at the end + M m = {0, 1}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct but key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the begin + M m = {1, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrectly in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 1; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the end + M m = {0, 3}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrect and key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace_hint(m.cbegin())), R); + R r = m.emplace_hint(m.end(), 2, 0.0); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp new file mode 100644 index 000000000000000..386af04d26e9a2e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(iterator position); +// iterator erase(const_iterator position); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(std::next(m.cbegin(), 3)); + assert(m.size() == 7); + assert(i1 == std::next(m.begin(), 3)); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 5); + assert(*std::next(m.begin(), 4) == 6); + assert(*std::next(m.begin(), 5) == 7); + assert(*std::next(m.begin(), 6) == 8); + + std::same_as decltype(auto) i2 = m.erase(std::next(m.begin(), 0)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 5)); + assert(m.size() == 5); + assert(i3 == m.end()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + + std::same_as decltype(auto) i4 = m.erase(std::next(m.begin(), 1)); + assert(m.size() == 4); + assert(i4 == std::next(m.begin())); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 6); + assert(*std::next(m.begin(), 3) == 7); + + std::same_as decltype(auto) i5 = m.erase(std::next(m.cbegin(), 2)); + assert(m.size() == 3); + assert(i5 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 7); + + std::same_as decltype(auto) i6 = m.erase(std::next(m.begin(), 2)); + assert(m.size() == 2); + assert(i6 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + + std::same_as decltype(auto) i7 = m.erase(std::next(m.cbegin(), 0)); + assert(m.size() == 1); + assert(i7 == std::next(m.begin(), 0)); + assert(*m.begin() == 5); + + std::same_as decltype(auto) i8 = m.erase(m.begin()); + assert(m.size() == 0); + assert(i8 == m.begin()); + assert(i8 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp new file mode 100644 index 000000000000000..7416977844e5df2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(const_iterator first, const_iterator last); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(m.cbegin(), m.cbegin()); + assert(m.size() == 8); + assert(i1 == m.begin()); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 4); + assert(*std::next(m.begin(), 4) == 5); + assert(*std::next(m.begin(), 5) == 6); + assert(*std::next(m.begin(), 6) == 7); + assert(*std::next(m.begin(), 7) == 8); + + std::same_as decltype(auto) i2 = m.erase(m.cbegin(), std::next(m.cbegin(), 2)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 2), std::next(m.cbegin(), 6)); + assert(m.size() == 2); + assert(i3 == std::next(m.begin(), 2)); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + + std::same_as decltype(auto) i4 = m.erase(m.cbegin(), m.cend()); + assert(m.size() == 0); + assert(i4 == m.begin()); + assert(i4 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp new file mode 100644 index 000000000000000..25d4f4af19608b4 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(const key_type& k); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template > +void test() { + using M = std::flat_set; + + auto make = [](std::initializer_list il) { + M m; + for (int i : il) { + m.emplace(i); + } + return m; + }; + M m = make({1, 2, 3, 4, 5, 6, 7, 8}); + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(9); + assert(n == 0); + assert(m == make({1, 2, 3, 4, 5, 6, 7, 8})); + n = m.erase(4); + assert(n == 1); + assert(m == make({1, 2, 3, 5, 6, 7, 8})); + n = m.erase(1); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7, 8})); + n = m.erase(8); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7})); + n = m.erase(3); + assert(n == 1); + assert(m == make({2, 5, 6, 7})); + n = m.erase(4); + assert(n == 0); + assert(m == make({2, 5, 6, 7})); + n = m.erase(6); + assert(n == 1); + assert(m == make({2, 5, 7})); + n = m.erase(7); + assert(n == 1); + assert(m == make({2, 5})); + n = m.erase(2); + assert(n == 1); + assert(m == make({5})); + n = m.erase(5); + assert(n == 1); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test, std::greater<>>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp new file mode 100644 index 000000000000000..cbf7cac603806d7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(K&& k); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanErase = requires(M m, Transparent k) { m.erase(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanErase); +static_assert(!CanErase); +static_assert(!CanErase); +static_assert(!CanErase); + +template +struct HeterogeneousKey { + explicit HeterogeneousKey(Key key, It it) : key_(key), it_(it) {} + operator It() && { return it_; } + auto operator<=>(Key key) const { return key_ <=> key; } + friend bool operator<(const HeterogeneousKey&, const HeterogeneousKey&) { + assert(false); + return false; + } + Key key_; + It it_; +}; + +template +void test_simple() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(3); // erase(K&&) [with K=int] + assert(n == 1); + assert((m == M{1, 2, 4})); + typename M::key_type lvalue = 2; + n = m.erase(lvalue); // erase(K&&) [with K=int&] + assert(n == 1); + assert((m == M{1, 4})); + const typename M::key_type const_lvalue = 1; + n = m.erase(const_lvalue); // erase(const key_type&) + assert(n == 1); + assert((m == M{4})); +} + +template +void test_transparent_comparator() { + using M = std::flat_set; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.erase(Transparent{"abc"})), typename M::size_type); + + auto n = m.erase(Transparent{"epsilon"}); + assert(n == 1); + + M expected = {"alpha", "beta", "eta", "gamma"}; + assert(m == expected); + + auto n2 = m.erase(Transparent{"aaa"}); + assert(n2 == 0); + assert(m == expected); +} + +int main(int, char**) { + test_simple>(); + test_simple>(); + test_simple>(); + test_simple>>(); + + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>>(); + + { + // P2077's HeterogeneousKey example + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.erase(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp new file mode 100644 index 000000000000000..c3bbffabb90a08f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// containers extract() &&; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanExtract = requires(T&& t) { std::forward(t).extract(); }; + +static_assert(CanExtract&&>); +static_assert(!CanExtract&>); +static_assert(!CanExtract const&>); +static_assert(!CanExtract const&&>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + M m = M({1, 2, 3}); + + std::same_as auto keys = std::move(m).extract(); + + auto expected_keys = {1, 2, 3}; + assert(std::ranges::equal(keys, expected_keys)); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // extracted object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m = M({1, 2, 3}); + std::same_as auto keys = std::move(m).extract(); + assert(keys.size() == 3); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); + } + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + auto c = std::move(m).extract(); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we try to erase the key after value emplacement failure. + // and after erasure failure, we clear the flat_set + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp new file mode 100644 index 000000000000000..c0ddadc30069872 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair insert(const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using VT = typename M::value_type; + M m; + + const VT v1(2); + std::same_as decltype(auto) r = m.insert(v1); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + + const VT v2(1); + r = m.insert(v2); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == 1); + + const VT v3(3); + r = m.insert(v3); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); + + const VT v4(3); + r = m.insert(v4); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp new file mode 100644 index 000000000000000..7381514a70eabbb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; + + M m = {1,1,1,3,3,3}; + m.insert({ + 4, + 4, + 4, + 1, + 1, + 1, + 2, + 2, + 2, + }); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(*m.begin() == V(1)); + assert(*std::next(m.begin()) == V(2)); + assert(*std::next(m.begin(), 2) == V(3)); + assert(*std::next(m.begin(), 3) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp new file mode 100644 index 000000000000000..c343d53a62215a8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator insert(const_iterator position, const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = typename M::iterator; + using VT = typename M::value_type; + + M m; + const VT v1(2); + std::same_as decltype(auto) r = m.insert(m.end(), v1); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + + const VT v2(1); + r = m.insert(m.end(), v2); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == 1); + + const VT v3(3); + r = m.insert(m.end(), v3); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); + + const VT v4(3); + r = m.insert(m.end(), v4); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp new file mode 100644 index 000000000000000..d20a8ef8fdd92d8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + + int ar1[] = { + 2, + 2, + 2, + 1, + 1, + 1, + 3, + 3, + 3, + }; + int ar2[] = { + 4, + 4, + 4, + 1, + 1, + 1, + 0, + 0, + 0, + }; + + M m; + m.insert(cpp17_input_iterator(ar1), cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(cpp17_input_iterator(ar2), cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp new file mode 100644 index 000000000000000..84b6c7fc1d34f62 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// +// iterator insert(const_iterator position, value_type&&); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "../helpers.h" +#include "test_macros.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + using R = typename M::iterator; + M m; + std::same_as decltype(auto) r = m.insert(m.end(), V(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == V(2)); + + r = m.insert(m.end(), V(1)); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == V(1)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp new file mode 100644 index 000000000000000..536307252c64058 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// void insert_range(R&& rg); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "MoveOnly.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint container-compatible-range +template +concept CanInsertRange = requires(M m, R&& r) { m.insert_range(std::forward(r)); }; + +using Set = std::flat_set; + +static_assert(CanInsertRange>); +static_assert(CanInsertRange>); +static_assert(!CanInsertRange*>>); +static_assert(!CanInsertRange*>>); + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using M = std::flat_set, KeyContainer>; + using It = forward_iterator; + M m = {10, 8, 5, 2, 1}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), It(ar + 6)}; + static_assert(std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9, 10})); + } + { + using M = std::flat_set, KeyContainer>; + using It = cpp20_input_iterator; + M m = {8, 5, 3, 2}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), sentinel_wrapper(It(ar + 6))}; + static_assert(!std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9})); + } + { + // The "uniquing" part uses the comparator, not operator==. + struct ModTen { + bool operator()(int a, int b) const { return (a % 10) < (b % 10); } + }; + using M = std::flat_set; + M m = {21, 43, 15, 37}; + int ar[] = {33, 18, 55, 18, 42}; + m.insert_range(ar); + assert((m == M{21, 42, 43, 15, 37, 18})); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // Items are forwarded correctly from the input range (P2767). + MoveOnly a[] = {3, 1, 4, 1, 5}; + std::flat_set m; + m.insert_range(a | std::views::as_rvalue); + MoveOnly expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + // The element type of the range doesn't need to be std::pair (P2767). + int pa[] = {3, 1, 4, 1, 5}; + std::deque> a(pa, pa + 5); + std::flat_set m; + m.insert_range(a); + int expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp new file mode 100644 index 000000000000000..7d95f0521eb1f67 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// pair insert( value_type&& v); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + using R = std::pair; + using V = typename M::value_type; + + M m; + std::same_as decltype(auto) r = m.insert(V(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == V(2)); + + r = m.insert(V(1)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == V(1)); + + r = m.insert(V(3)); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); + + r = m.insert(V(3)); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp new file mode 100644 index 000000000000000..fa5bf86830daecd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(sorted_unique_t, initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + M m = {1, 1, 1, 3, 3, 3}; + m.insert(std::sorted_unique, {0, 1, 2, 4}); + assert(m.size() == 5); + assert(std::distance(m.begin(), m.end()) == 5); + assert(*m.begin() == V(0)); + assert(*std::next(m.begin()) == V(1)); + assert(*std::next(m.begin(), 2) == V(2)); + assert(*std::next(m.begin(), 3) == V(3)); + assert(*std::next(m.begin(), 4) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp new file mode 100644 index 000000000000000..ef7b8391cee33c1 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(sorted_unique_t, InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + int ar1[] = {1, 2, 3}; + + int ar2[] = {0, 2, 4}; + + M m; + m.insert(std::sorted_unique, + cpp17_input_iterator(ar1), + cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(std::sorted_unique, + cpp17_input_iterator(ar2), + cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp new file mode 100644 index 000000000000000..72d7261a1825477 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -0,0 +1,169 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair insert(P&& x); +// template iterator insert(const_iterator hint, P&& x); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// Constraints: is_constructible_v is true. +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; +using Iter = Set::const_iterator; + +static_assert(CanInsert); +static_assert(CanInsert); +static_assert(!CanInsert); +static_assert(!CanInsert); + +static int expensive_comparisons = 0; +static int cheap_comparisons = 0; + +struct CompareCounter { + int i_ = 0; + CompareCounter(int i) : i_(i) {} + friend auto operator<=>(const CompareCounter& x, const CompareCounter& y) { + expensive_comparisons += 1; + return x.i_ <=> y.i_; + } + bool operator==(const CompareCounter&) const = default; + friend auto operator<=>(const CompareCounter& x, int y) { + cheap_comparisons += 1; + return x.i_ <=> y; + } +}; + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + const int expected[] = {1, 2, 3, 4, 5}; + { + // insert(P&&) + // Unlike flat_set, here we can't use key_compare to compare value_type versus P, + // so we must eagerly convert to value_type. + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, P&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // insert(value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens last + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // emplace(Args&&...) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.emplace(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // no ambiguity between insert(pos, P&&) and insert(first, last) + using M = std::flat_set; + struct Evil { + operator M::value_type() const; + operator M::const_iterator() const; + }; + std::flat_set m; + ASSERT_SAME_TYPE(decltype(m.insert(Evil())), std::pair); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); + } + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(t); + }; + test_emplace_exception_guarantee(insert_func); + } + { + auto insert_func_iter = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(m.begin(), t); + }; + test_emplace_exception_guarantee(insert_func_iter); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp new file mode 100644 index 000000000000000..49cb6eb6163c903 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void replace(container_type&& key_cont); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanReplace = requires(T t, Args&&... args) { t.replace(std::forward(args)...); }; + +using Set = std::flat_set; +static_assert(CanReplace>); +static_assert(!CanReplace&>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = M({1, 2, 3}); + KeyContainer new_keys = {7, 8}; + auto expected_keys = new_keys; + m.replace(std::move(new_keys)); + assert(m.size() == 2); + assert(std::ranges::equal(m, expected_keys)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp new file mode 100644 index 000000000000000..23a2dc85989bb7f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// `check_assertion.h` requires Unix headers and regex support. +// REQUIRES: has-unix-headers +// UNSUPPORTED: no-localization +// UNSUPPORTED: no-exceptions + +// + +// void swap(flat_set& y) noexcept; +// friend void swap(flat_set& x, flat_set& y) noexcept + +// Test that std::terminate is called if any exception is thrown during swap + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../helpers.h" +#include "check_assertion.h" + +template +void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) { + { + // key swap throws + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m1, m2; + m1.emplace(1); + m1.emplace(2); + m2.emplace(3); + m2.emplace(4); + // swap is noexcept + EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); }); + } +} + +int main(int, char**) { + { + auto swap_func = [](auto& m1, auto& m2) { swap(m1, m2); }; + test_swap_exception_guarantee(swap_func); + } + + { + auto swap_func = [](auto& m1, auto& m2) { m1.swap(m2); }; + test_swap_exception_guarantee(swap_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp new file mode 100644 index 000000000000000..bc7baa67e52a599 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend void swap(flat_set& x, flat_set& y) noexcept + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptAdlSwap = requires(T t1, T t2) { + { swap(t1, t2) } noexcept; +}; + +static_assert(NoExceptAdlSwap>); + +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptAdlSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp new file mode 100644 index 000000000000000..b0b06a9499efc7a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void swap(flat_set& y) noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptMemberSwap = requires(T t1, T t2) { + { t1.swap(t2) } noexcept; +}; + +static_assert(NoExceptMemberSwap>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptMemberSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp new file mode 100644 index 000000000000000..971b5e1c338dd11 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// key_compare key_comp() const; +// value_compare value_comp() const; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + { + using M = std::flat_set; + using Comp = std::less; // the default + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + { + using Comp = std::function; + using M = std::flat_set; + Comp comp = std::greater(); + M m({}, comp); + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(!kc(1, 2)); + assert(kc(2, 1)); + auto vc = m.value_comp(); + assert(!vc(1, 2)); + assert(vc(2, 1)); + } + { + using Comp = std::less<>; + using M = std::flat_set; + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + auto a = std::make_pair(1, 2); + ASSERT_SAME_TYPE(decltype(vc(a, a)), bool); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp new file mode 100644 index 000000000000000..b14da66f611301e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// bool contains(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp new file mode 100644 index 000000000000000..507560608952b01 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template bool contains(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanContains = requires(M m, Transparent k) { m.contains(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanContains); +static_assert(CanContains); +static_assert(!CanContains); +static_assert(!CanContains); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.contains(Transparent{"abc"})), bool); + ASSERT_SAME_TYPE(decltype(std::as_const(m).contains(Transparent{"b"})), bool); + assert(m.contains(Transparent{"alpha"}) == true); + assert(m.contains(Transparent{"beta"}) == true); + assert(m.contains(Transparent{"epsilon"}) == true); + assert(m.contains(Transparent{"eta"}) == true); + assert(m.contains(Transparent{"gamma"}) == true); + assert(m.contains(Transparent{"al"}) == false); + assert(m.contains(Transparent{""}) == false); + assert(m.contains(Transparent{"g"}) == false); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto b = m.contains(Transparent{3}); + assert(b); + assert(transparent_used); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp new file mode 100644 index 000000000000000..478f615358b6068 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type count(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using S = typename KeyContainer::size_type; + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp new file mode 100644 index 000000000000000..b591258f74399c8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template size_type count(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanCount = requires(M m, Transparent k) { m.count(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanCount); +static_assert(CanCount); +static_assert(!CanCount); +static_assert(!CanCount); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.count(Transparent{"abc"})), typename M::size_type); + ASSERT_SAME_TYPE(decltype(std::as_const(m).count(Transparent{"b"})), typename M::size_type); + assert(m.count(Transparent{"alpha"}) == 1); + assert(m.count(Transparent{"beta"}) == 1); + assert(m.count(Transparent{"epsilon"}) == 1); + assert(m.count(Transparent{"eta"}) == 1); + assert(m.count(Transparent{"gamma"}) == 1); + assert(m.count(Transparent{"al"}) == 0); + assert(m.count(Transparent{""}) == 0); + assert(m.count(Transparent{"g"}) == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.count(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp new file mode 100644 index 000000000000000..a088b7fee17d2ca --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair equal_range(const key_type& k); +// pair equal_range(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin, begin)); + assert(m.equal_range(1) == std::pair(begin, begin + 1)); + assert(m.equal_range(2) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(3) == std::pair(begin + 2, begin + 2)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(6) == std::pair(begin + 4, begin + 4)); + assert(m.equal_range(7) == std::pair(begin + 4, begin + 4)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin() + 4, m.cbegin() + 5)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin() + 5, m.cbegin() + 5)); + } + + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin + 5, begin + 5)); + assert(m.equal_range(1) == std::pair(begin + 4, begin + 5)); + assert(m.equal_range(2) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(3) == std::pair(begin + 3, begin + 3)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(6) == std::pair(begin + 1, begin + 1)); + assert(m.equal_range(7) == std::pair(begin + 1, begin + 1)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin(), m.cbegin() + 1)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin(), m.cbegin())); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp new file mode 100644 index 000000000000000..ede5d91e19b9fdd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair equal_range(const K& x); +// template pair equal_range(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanEqualRange = requires(M m, Transparent k) { m.equal_range(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanEqualRange); +static_assert(CanEqualRange); +static_assert(!CanEqualRange); +static_assert(!CanEqualRange); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + using R = std::pair; + using CR = std::pair; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.equal_range(Transparent{"abc"})), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(Transparent{"b"})), CR); + + auto test_found = [&](auto&& map, const std::string& expected_key) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(last - first == 1); + assert(*first == expected_key); + }; + + auto test_not_found = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(first == last); + assert(first - m.begin() == expected_offset); + }; + + test_found(m, "alpha"); + test_found(m, "beta"); + test_found(m, "epsilon"); + test_found(m, "eta"); + test_found(m, "gamma"); + test_found(cm, "alpha"); + test_found(cm, "beta"); + test_found(cm, "epsilon"); + test_found(cm, "eta"); + test_found(cm, "gamma"); + + test_not_found(m, "charlie", 2); + test_not_found(m, "aaa", 0); + test_not_found(m, "zzz", 5); + test_not_found(cm, "charlie", 2); + test_not_found(cm, "aaa", 0); + test_not_found(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto p = m.equal_range(Transparent{3}); + assert(p.first != p.second); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp new file mode 100644 index 000000000000000..cf0dd2d1dd831c8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator find(const key_type& k); +// const_iterator find(const key_type& k) const; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.find(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(0)), typename M::const_iterator); + assert(m.find(0) == m.end()); + assert(m.find(1) == m.begin()); + assert(m.find(2) == m.begin() + 1); + assert(m.find(3) == m.end()); + assert(m.find(4) == m.begin() + 2); + assert(m.find(5) == m.begin() + 3); + assert(m.find(6) == m.end()); + assert(m.find(7) == m.end()); + assert(std::as_const(m).find(8) == m.begin() + 4); + assert(std::as_const(m).find(9) == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp new file mode 100644 index 000000000000000..730a57b0a6cb855 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator find(const K& x); +// template const_iterator find(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanFind = requires(M m, Transparent k) { m.find(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanFind); +static_assert(CanFind); +static_assert(!CanFind); +static_assert(!CanFind); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.find(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(Transparent{"b"})), typename M::const_iterator); + + auto test_find = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.find(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_find(m, "alpha", 0); + test_find(m, "beta", 1); + test_find(m, "epsilon", 2); + test_find(m, "eta", 3); + test_find(m, "gamma", 4); + test_find(m, "charlie", 5); + test_find(m, "aaa", 5); + test_find(m, "zzz", 5); + test_find(cm, "alpha", 0); + test_find(cm, "beta", 1); + test_find(cm, "epsilon", 2); + test_find(cm, "eta", 3); + test_find(cm, "gamma", 4); + test_find(cm, "charlie", 5); + test_find(cm, "aaa", 5); + test_find(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.find(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp new file mode 100644 index 000000000000000..093c32e537ed35f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator lower_bound(const key_type& k); +// const_iterator lower_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.begin()); + assert(m.lower_bound(1) == m.begin()); + assert(m.lower_bound(2) == m.begin() + 1); + assert(m.lower_bound(3) == m.begin() + 2); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 3); + assert(m.lower_bound(6) == m.begin() + 4); + assert(m.lower_bound(7) == m.begin() + 4); + assert(std::as_const(m).lower_bound(8) == m.begin() + 4); + assert(std::as_const(m).lower_bound(9) == m.end()); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.end()); + assert(m.lower_bound(1) == m.begin() + 4); + assert(m.lower_bound(2) == m.begin() + 3); + assert(m.lower_bound(3) == m.begin() + 3); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 1); + assert(m.lower_bound(6) == m.begin() + 1); + assert(m.lower_bound(7) == m.begin() + 1); + assert(std::as_const(m).lower_bound(8) == m.begin()); + assert(std::as_const(m).lower_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp new file mode 100644 index 000000000000000..18f9bc6dd329553 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator lower_bound(const K& x); +// template const_iterator lower_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanLowerBound = requires(M m, Transparent k) { m.lower_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanLowerBound); +static_assert(CanLowerBound); +static_assert(!CanLowerBound); +static_assert(!CanLowerBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_lower_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.lower_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_lower_bound(m, "abc", 0); + test_lower_bound(m, "alpha", 0); + test_lower_bound(m, "beta", 1); + test_lower_bound(m, "bets", 2); + test_lower_bound(m, "charlie", 2); + test_lower_bound(m, "echo", 2); + test_lower_bound(m, "epsilon", 2); + test_lower_bound(m, "eta", 3); + test_lower_bound(m, "gamma", 4); + test_lower_bound(m, "golf", 5); + test_lower_bound(m, "zzz", 5); + + test_lower_bound(cm, "abc", 0); + test_lower_bound(cm, "alpha", 0); + test_lower_bound(cm, "beta", 1); + test_lower_bound(cm, "bets", 2); + test_lower_bound(cm, "charlie", 2); + test_lower_bound(cm, "echo", 2); + test_lower_bound(cm, "epsilon", 2); + test_lower_bound(cm, "eta", 3); + test_lower_bound(cm, "gamma", 4); + test_lower_bound(cm, "golf", 5); + test_lower_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.lower_bound(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp new file mode 100644 index 000000000000000..ab34de851031756 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator upper_bound(const key_type& k); +// const_iterator upper_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.begin()); + assert(m.upper_bound(1) == m.begin() + 1); + assert(m.upper_bound(2) == m.begin() + 2); + assert(m.upper_bound(3) == m.begin() + 2); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 4); + assert(m.upper_bound(6) == m.begin() + 4); + assert(std::as_const(m).upper_bound(7) == m.begin() + 4); + assert(std::as_const(m).upper_bound(8) == m.end()); + assert(std::as_const(m).upper_bound(9) == m.end()); + } + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.end()); + assert(m.upper_bound(1) == m.end()); + assert(m.upper_bound(2) == m.begin() + 4); + assert(m.upper_bound(3) == m.begin() + 3); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 2); + assert(m.upper_bound(6) == m.begin() + 1); + assert(m.upper_bound(7) == m.begin() + 1); + assert(std::as_const(m).upper_bound(8) == m.begin() + 1); + assert(std::as_const(m).upper_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp new file mode 100644 index 000000000000000..69ce2ae926a305e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator upper_bound(const K& x); +// template const_iterator upper_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanUpperBound = requires(M m, Transparent k) { m.upper_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanUpperBound); +static_assert(CanUpperBound); +static_assert(!CanUpperBound); +static_assert(!CanUpperBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_upper_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.upper_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_upper_bound(m, "abc", 0); + test_upper_bound(m, "alpha", 1); + test_upper_bound(m, "beta", 2); + test_upper_bound(m, "bets", 2); + test_upper_bound(m, "charlie", 2); + test_upper_bound(m, "echo", 2); + test_upper_bound(m, "epsilon", 3); + test_upper_bound(m, "eta", 4); + test_upper_bound(m, "gamma", 5); + test_upper_bound(m, "golf", 5); + test_upper_bound(m, "zzz", 5); + + test_upper_bound(cm, "abc", 0); + test_upper_bound(cm, "alpha", 1); + test_upper_bound(cm, "beta", 2); + test_upper_bound(cm, "bets", 2); + test_upper_bound(cm, "charlie", 2); + test_upper_bound(cm, "echo", 2); + test_upper_bound(cm, "epsilon", 3); + test_upper_bound(cm, "eta", 4); + test_upper_bound(cm, "gamma", 5); + test_upper_bound(cm, "golf", 5); + test_upper_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.upper_bound(Transparent{2}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h new file mode 100644 index 000000000000000..9fff262d84234e9 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -0,0 +1,294 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_flat_set_HELPERS_H +#define SUPPORT_flat_set_HELPERS_H + +#include +#include +#include +#include +#include + +#include "test_allocator.h" +#include "test_macros.h" + +template +void check_invariant(const std::flat_set& m) { + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); + auto key_equal = [&](const auto& x, const auto& y) { + const auto& c = m.key_comp(); + return !c(x, y) && !c(y, x); + }; + assert(std::adjacent_find(m.begin(), m.end(), key_equal) == m.end()); +} + +struct StartsWith { + explicit StartsWith(char ch) : lower_(1, ch), upper_(1, ch + 1) {} + StartsWith(const StartsWith&) = delete; + void operator=(const StartsWith&) = delete; + struct Less { + using is_transparent = void; + bool operator()(const std::string& a, const std::string& b) const { return a < b; } + bool operator()(const StartsWith& a, const std::string& b) const { return a.upper_ <= b; } + bool operator()(const std::string& a, const StartsWith& b) const { return a < b.lower_; } + bool operator()(const StartsWith&, const StartsWith&) const { + assert(false); // should not be called + return false; + } + }; + +private: + std::string lower_; + std::string upper_; +}; + +template +struct CopyOnlyVector : std::vector { + using std::vector::vector; + + CopyOnlyVector(const CopyOnlyVector&) = default; + CopyOnlyVector(CopyOnlyVector&& other) : CopyOnlyVector(other) {} + CopyOnlyVector(CopyOnlyVector&& other, std::vector::allocator_type alloc) : CopyOnlyVector(other, alloc) {} + + CopyOnlyVector& operator=(const CopyOnlyVector&) = default; + CopyOnlyVector& operator=(CopyOnlyVector& other) { return this->operator=(other); } +}; + +template +struct Transparent { + T t; + + operator T() const + requires ConvertibleToT + { + return t; + } +}; + +template +using ConvertibleTransparent = Transparent; + +template +using NonConvertibleTransparent = Transparent; + +struct TransparentComparator { + using is_transparent = void; + + bool* transparent_used = nullptr; + TransparentComparator() = default; + TransparentComparator(bool& used) : transparent_used(&used) {} + + template + bool operator()(const T& t, const Transparent& transparent) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return t < transparent.t; + } + + template + bool operator()(const Transparent& transparent, const T& t) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return transparent.t < t; + } + + template + bool operator()(const T& t1, const T& t2) const { + return t1 < t2; + } +}; + +struct NonTransparentComparator { + template + bool operator()(const T&, const Transparent&) const; + + template + bool operator()(const Transparent&, const T&) const; + + template + bool operator()(const T&, const T&) const; +}; + +struct NoDefaultCtr { + NoDefaultCtr() = delete; +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +struct EmplaceUnsafeContainer : std::vector { + using std::vector::vector; + + template + auto emplace(Args&&... args) -> decltype(std::declval>().emplace(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } + + template + auto insert(Args&&... args) -> decltype(std::declval>().insert(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } +}; + +template +struct ThrowOnEraseContainer : std::vector { + using std::vector::vector; + + template + auto erase(Args&&... args) -> decltype(std::declval>().erase(std::forward(args)...)) { + throw 42; + } +}; + +template +struct ThrowOnMoveContainer : std::vector { + using std::vector::vector; + + ThrowOnMoveContainer(ThrowOnMoveContainer&&) { throw 42; } + + ThrowOnMoveContainer& operator=(ThrowOnMoveContainer&&) { throw 42; } +}; + +#endif + +template +void test_emplace_exception_guarantee([[maybe_unused]] F&& emplace_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using C = TransparentComparator; + { + // Throw on emplace the key, and underlying has strong exception guarantee + using KeyContainer = std::vector>; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + + test_allocator_statistics stats; + + KeyContainer a({1, 2, 3, 4}, test_allocator{&stats}); + [[maybe_unused]] auto expected_keys = a; + M m(std::sorted_unique, std::move(a)); + + stats.throw_after = 1; + try { + emplace_function(m, 0); + assert(false); + } catch (const std::bad_alloc&) { + check_invariant(m); + // In libc++, the flat_set is unchanged + LIBCPP_ASSERT(m.size() == 4); + LIBCPP_ASSERT(std::ranges::equal(m, expected_keys)); + } + } + { + // Throw on emplace the key, and underlying has no strong exception guarantee + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(!std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + KeyContainer a = {1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + emplace_function(m, 0); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, the flat_set is cleared + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} + +template +void test_insert_range_exception_guarantee([[maybe_unused]] F&& insert_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + test_allocator_statistics stats; + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + + std::vector newValues = {0, 1, 5, 6, 7, 8}; + stats.throw_after = 1; + try { + insert_function(m, newValues); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when inserting a range + LIBCPP_ASSERT(m.size() == 0); + } +#endif +} + +template +void test_erase_exception_guarantee([[maybe_unused]] F&& erase_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + { + // key erase throws + using KeyContainer = ThrowOnEraseContainer; + using M = std::flat_set; + + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + erase_function(m, 3); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when erasing + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} +class Moveable { + int int_; + double double_; + +public: + Moveable() : int_(0), double_(0) {} + Moveable(int i, double d) : int_(i), double_(d) {} + Moveable(Moveable&& x) : int_(x.int_), double_(x.double_) { + x.int_ = -1; + x.double_ = -1; + } + Moveable& operator=(Moveable&& x) { + int_ = x.int_; + x.int_ = -1; + double_ = x.double_; + x.double_ = -1; + return *this; + } + + Moveable(const Moveable&) = delete; + Moveable& operator=(const Moveable&) = delete; + bool operator==(const Moveable& x) const { return int_ == x.int_ && double_ == x.double_; } + bool operator<(const Moveable& x) const { return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_); } + + int get() const { return int_; } + bool moved() const { return int_ == -1; } +}; + +#endif // SUPPORT_flat_set_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp new file mode 100644 index 000000000000000..c4a9810016536bd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Check that std::flat_set and its iterators can be instantiated with an incomplete +// type. + +#include +#include + +struct A { + using Set = std::flat_set; + int data; + Set m; + Set::iterator it; + Set::const_iterator cit; +}; + +// Implement the operator< required in order to instantiate flat_set +bool operator<(A const& L, A const& R) { return L.data < R.data; } + +int main(int, char**) { + A a; + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp new file mode 100644 index 000000000000000..f6d08bb736d3004 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend bool operator==(const flat_set& x, const flat_set& y); +// friend synth-three-way-result +// operator<=>(const flat_set& x, const flat_set& y); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_comparisons.h" +#include "test_container_comparisons.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, true)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } + { + // Comparisons use value_type's native operators, not the comparator + using C = std::flat_set>; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, false)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = C(std::sorted_unique, {std::numeric_limits::quiet_NaN()}); + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + } + { + // Comparisons use value_type's native operators, not the comparator + struct StrongComp { + bool operator()(double a, double b) const { return std::strong_order(a, b) < 0; } + }; + using C = std::flat_set; + C s1 = {1}; + C s2 = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + s1 = {1, std::numeric_limits::quiet_NaN(), 1}; + s2 = {std::numeric_limits::quiet_NaN(), 1}; + assert(std::lexicographical_compare_three_way(s1.begin(), s1.end(), s2.begin(), s2.end(), std::strong_order) == + std::strong_ordering::equal); + assert(s1 != s2); + assert((s1 <=> s2) == std::partial_ordering::unordered); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp new file mode 100644 index 000000000000000..a845b2b81e89d35 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// using key_type = Key; +// using value_type = Key; +// using key_compare = Compare; +// using value_compare = Compare; +// using reference = value_type&; +// using const_reference = const value_type&; +// using size_type = typename KeyContainer::size_type; +// using difference_type = typename KeyContainer::difference_type; +// using iterator = implementation-defined; // see [container.requirements] +// using const_iterator = implementation-defined; // see [container.requirements] +// using reverse_iterator = std::reverse_iterator; +// using const_reverse_iterator = std::reverse_iterator; +// using container_type = KeyContainer; + +#include +#include +#include +#include +#include +#include +#include +#include "min_allocator.h" + +void test() { + { + using M = std::flat_set; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(requires { typename M::value_compare; }); + } + + { + struct A {}; + struct Compare { + bool operator()(const std::string&, const std::string&) const; + }; + using M = std::flat_set>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + } + { + using C = std::flat_set, std::deque>>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + // size_type is invariably size_t + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>>); + } +} >From 96903d9c8f1ea42de65fbe1a07e59413a1630d1e Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 13:21:24 +0000 Subject: [PATCH 2/7] review --- libcxx/include/__flat_set/flat_set.h | 137 +++---- .../flat.set/flat.set.capacity/empty.pass.cpp | 14 +- .../flat.set.capacity/max_size.pass.cpp | 8 +- .../flat.set/flat.set.capacity/size.pass.cpp | 14 +- .../flat.set/flat.set.cons/alloc.pass.cpp | 6 +- .../assign_initializer_list.pass.cpp | 19 +- .../flat.set/flat.set.cons/compare.pass.cpp | 6 +- .../flat.set.cons/containers.pass.cpp | 25 +- .../flat.set/flat.set.cons/copy.pass.cpp | 6 +- .../flat.set.cons/copy_alloc.pass.cpp | 6 +- .../copy_assign.addressof.compile.pass.cpp | 30 -- .../flat.set.cons/copy_assign.pass.cpp | 17 +- .../flat.set/flat.set.cons/deduct.pass.cpp | 353 +++++++++--------- .../flat.set/flat.set.cons/default.pass.cpp | 36 +- .../flat.set.cons/default_noexcept.pass.cpp | 58 --- .../flat.set.cons/dtor_noexcept.pass.cpp | 6 +- .../flat.set.cons/initializer_list.pass.cpp | 6 +- .../flat.set/flat.set.cons/iter_iter.pass.cpp | 6 +- .../flat.set/flat.set.cons/move.pass.cpp | 107 +++++- .../flat.set.cons/move_alloc.pass.cpp | 10 +- .../flat.set.cons/move_assign.pass.cpp | 141 ++++++- .../flat.set.cons/move_assign_clears.pass.cpp | 101 ----- .../move_assign_noexcept.pass.cpp | 85 ----- .../flat.set.cons/move_exceptions.pass.cpp | 58 --- .../flat.set.cons/move_noexcept.pass.cpp | 94 ----- .../flat.set/flat.set.cons/pmr.pass.cpp | 6 +- .../flat.set/flat.set.cons/range.pass.cpp | 6 +- .../flat.set.cons/sorted_container.pass.cpp | 6 +- .../sorted_initializer_list.pass.cpp | 10 +- .../flat.set.cons/sorted_iter_iter.pass.cpp | 6 +- .../flat.set.erasure/erase_if.pass.cpp | 20 +- .../erase_if_exceptions.pass.cpp | 7 +- .../flat.set.iterators/iterator.pass.cpp | 18 +- .../iterator_comparison.pass.cpp | 14 +- .../reverse_iterator.pass.cpp | 8 +- .../flat.set.modifiers/clear.pass.cpp | 18 +- .../flat.set.modifiers/emplace.pass.cpp | 25 +- .../flat.set.modifiers/emplace_hint.pass.cpp | 25 +- .../flat.set.modifiers/erase_iter.pass.cpp | 25 +- .../erase_iter_iter.pass.cpp | 24 +- .../flat.set.modifiers/erase_key.pass.cpp | 37 +- .../erase_key_transparent.pass.cpp | 34 +- .../flat.set.modifiers/extract.pass.cpp | 21 +- .../flat.set.modifiers/insert_cv.pass.cpp | 33 +- .../insert_initializer_list.pass.cpp | 42 ++- .../insert_iter_cv.pass.cpp | 23 +- .../insert_iter_iter.pass.cpp | 27 +- .../insert_iter_rv.pass.cpp | 43 ++- .../flat.set.modifiers/insert_range.pass.cpp | 38 +- .../flat.set.modifiers/insert_rv.pass.cpp | 42 ++- .../insert_sorted_initializer_list.pass.cpp | 35 +- .../insert_sorted_iter_iter.pass.cpp | 29 +- .../insert_transparent.pass.cpp | 21 +- .../flat.set.modifiers/replace.pass.cpp | 50 +-- .../flat.set.modifiers/swap_free.pass.cpp | 16 +- .../flat.set.modifiers/swap_member.pass.cpp | 14 +- .../flat.set/flat.set.observers/comp.pass.cpp | 6 +- .../flat.set.operations/contains.pass.cpp | 14 +- .../contains_transparent.pass.cpp | 17 +- .../flat.set.operations/count.pass.cpp | 14 +- .../count_transparent.pass.cpp | 16 +- .../flat.set.operations/equal_range.pass.cpp | 14 +- .../equal_range_transparent.pass.cpp | 16 +- .../flat.set.operations/find.pass.cpp | 14 +- .../find_transparent.pass.cpp | 16 +- .../flat.set.operations/lower_bound.pass.cpp | 14 +- .../lower_bound_transparent.pass.cpp | 16 +- .../flat.set.operations/upper_bound.pass.cpp | 14 +- .../upper_bound_transparent.pass.cpp | 17 +- .../container.adaptors/flat.set/helpers.h | 19 +- .../flat.set/incomplete_type.pass.cpp | 5 +- .../flat.set/op_compare.pass.cpp | 17 +- 72 files changed, 1214 insertions(+), 1087 deletions(-) delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index c920632c453bf5e..37e4c9f7c686b00 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP___FLAT_set_FLAT_SET_H -#define _LIBCPP___FLAT_set_FLAT_SET_H +#ifndef _LIBCPP___FLAT_SET_FLAT_SET_H +#define _LIBCPP___FLAT_SET_FLAT_SET_H #include <__algorithm/lexicographical_compare_three_way.h> #include <__algorithm/min.h> @@ -99,13 +99,6 @@ class flat_set { using const_reverse_iterator = std::reverse_iterator; using container_type = _KeyContainer; -private: - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = - uses_allocator::value; - - _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; - public: // [flat.set.cons], construct/copy/destroy _LIBCPP_HIDE_FROM_ABI @@ -178,31 +171,31 @@ class flat_set { : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( @@ -210,7 +203,7 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { @@ -219,12 +212,12 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) # if _LIBCPP_HAS_EXCEPTIONS try @@ -239,14 +232,14 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert(__first, __last); } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { @@ -254,7 +247,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { @@ -262,7 +255,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, @@ -274,37 +267,37 @@ class flat_set { } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert_range(std::forward<_Range>(__rg)); } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { insert_range(std::forward<_Range>(__rg)); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} @@ -334,11 +327,8 @@ class flat_set { // iterators _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } @@ -382,7 +372,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { return emplace(std::forward<_Kp>(__x)); } @@ -395,7 +385,7 @@ class flat_set { } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { return emplace_hint(__hint, std::forward<_Kp>(__x)); } @@ -425,7 +415,7 @@ class flat_set { __reserve(ranges::size(__range)); } - __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + __append_sort_merge_unique(std::forward<_Range>(__range)); } _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } @@ -468,7 +458,7 @@ class flat_set { } template - requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> && !is_convertible_v<_Kp &&, const_iterator>) _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { auto [__first, __last] = equal_range(__x); @@ -505,13 +495,13 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { return __find_impl(*this, __x); } @@ -519,7 +509,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { return contains(__x) ? 1 : 0; } @@ -527,7 +517,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { return find(__x) != end(); } @@ -541,13 +531,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { return ranges::lower_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { return ranges::lower_bound(__keys_, __x, __compare_); } @@ -561,13 +551,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { return ranges::upper_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { return ranges::upper_bound(__keys_, __x, __compare_); } @@ -581,12 +571,12 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { return __equal_range_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { return __equal_range_impl(*this, __x); } @@ -611,14 +601,14 @@ class flat_set { }; template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), __compare_(std::forward<_CompArg>(__comp)...) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc)), __compare_(std::forward<_CompArg>(__comp)...) {} @@ -637,17 +627,30 @@ class flat_set { __keys_.erase(__dup_start, __keys_.end()); } - template - _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { - auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); - size_type __old_size = size(); - if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { - __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + template + _LIBCPP_HIDE_FROM_ABI void __append(_InputIterator __first, _InputIterator __last) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append(_Range&& __rng) { + if constexpr (requires { __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); }) { + // C++23 Sequence Container should have insert_range member function + __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); + } else if constexpr (ranges::common_range<_Range>) { + __keys_.insert(__keys_.end(), ranges::begin(__rng), ranges::end(__rng)); } else { - for (; __first != __last; ++__first) { - __keys_.insert(__keys_.end(), *__first); + for (auto&& __x : __rng) { + __keys_.insert(__keys_.end(), std::forward(__x)); } } + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_Args&&... __args) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + __append(std::forward<_Args>(__args)...); if (size() != __old_size) { if constexpr (!_WasSorted) { ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); @@ -831,18 +834,18 @@ template struct uses_allocator, _Allocator> : bool_constant> {}; - template - _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type - erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { - auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); - auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { - return static_cast(__pred(e)); - }); - auto __res = __flat_set.__keys_.end() - __it; - __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); - __guard.__complete(); - return __res; - } +template +_LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type +erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; +} _LIBCPP_END_NAMESPACE_STD @@ -850,4 +853,4 @@ _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS -#endif // _LIBCPP___FLAT_set_FLAT_SET_H +#endif // _LIBCPP___FLAT_SET_FLAT_SET_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp index 204df1d681af1bc..223b92fc3e8e84f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m; @@ -38,11 +38,15 @@ void test() { assert(m.empty()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index cd7f424e00ece23..0489d8862579119 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -24,7 +24,8 @@ #include "test_allocator.h" #include "test_macros.h" -int main(int, char**) { +void test() { + { using A1 = limited_allocator; using C = std::flat_set, std::vector>; @@ -59,5 +60,10 @@ int main(int, char**) { assert(c.max_size() <= max_dist); assert(c.max_size() <= alloc_max_size(std::allocator())); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp index 7c156e95ecb1c86..9f5ffdd06635133 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; using S = typename M::size_type; { @@ -56,11 +56,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp index acc0817d7cac4d6..d14e883dd5e9362 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -22,7 +22,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -55,6 +55,10 @@ int main(int, char**) { auto v = std::move(m).extract(); assert(v.get_allocator().get_id() == 5); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7f75f1e1611e3b4..7e948d7c5fe976b 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -33,7 +33,6 @@ void test() { m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); - LIBCPP_ASSERT(std::ranges::equal(m, expected)); } { M m = {10, 8}; @@ -44,13 +43,17 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp index b3bee18f5a936b1..110757a1bb9ab6a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -78,6 +78,10 @@ int main(int, char**) { auto keys = std::move(m).extract(); assert(keys.get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp index 3d1e6240c952e8c..6b1246885bf5276 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -36,7 +36,7 @@ void conversion_test(T); template concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -116,21 +116,16 @@ int main(int, char**) { auto m = M(ks, A(4)); // replaces the allocators assert(!ks.empty()); // it was an lvalue above assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); + auto keys = M(m).extract(); assert(keys.get_allocator() == A(4)); - } - { - // flat_set(container_type , const Allocator&) + // explicit(false) - using A = test_allocator; - using M = std::flat_set, std::deque>; static_assert(ImplicitlyConstructible&, const A&>); - auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); - M m = {ks, A(4)}; // implicit ctor - assert(!ks.empty()); // it was an lvalue above - assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); - assert(keys.get_allocator() == A(4)); + M m2 = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert(m2 == m); + auto keys2 = std::move(m).extract(); + assert(keys2.get_allocator() == A(4)); } { // flat_set(container_type , key_compare, const Allocator&) @@ -153,6 +148,10 @@ int main(int, char**) { keys = std::move(m2).extract(); assert(keys.get_allocator() == A(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp index f1dbc955e1b0de7..1ba550d98f01f6d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -21,7 +21,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; std::vector> ks({1, 3, 5}, test_allocator(6)); @@ -59,6 +59,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == other_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp index 59fb9d0a38366fe..5011bd200306419 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -23,7 +23,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -58,6 +58,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == test_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp deleted file mode 100644 index 169b469f3bca68b..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp +++ /dev/null @@ -1,30 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(const flat_set& s); - -// Validate whether the container can be copy-assigned (move-assigned, swapped) -// with an ADL-hijacking operator& - -#include -#include - -#include "test_macros.h" -#include "operator_hijacker.h" - -void test() { - std::flat_set so; - std::flat_set s; - s = so; - s = std::move(so); - swap(s, so); -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp index cdd5045f4bb9f7e..695363e3aeababe 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -17,11 +17,12 @@ #include #include +#include "operator_hijacker.h" #include "test_macros.h" #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // test_allocator is not propagated using C = test_less; @@ -81,5 +82,19 @@ int main(int, char**) { m = static_cast(m); assert((m == M{{1, 2}})); } + { + // Validate whether the container can be copy-assigned (move-assigned, swapped) + // with an ADL-hijacking operator& + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); + } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp index 612e64a7c42f23e..607fe0d1a9713a9 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -26,24 +26,21 @@ #include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" -using P = std::pair; -using PC = std::pair; - void test_copy() { { - std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set source = {1, 2}; std::flat_set s(source); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s{source}; // braces instead of parens ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s(source, std::allocator()); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); @@ -52,275 +49,259 @@ void test_copy() { void test_containers() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); - std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + int expected[] = {1, 2, 3, INT_MAX}; { - std::flat_set s(ks, vs); + std::flat_set s(ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + std::flat_set s(std::sorted_unique, sorted_ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, test_allocator(0, 44)); + std::flat_set s(ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_containers_compare() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); - std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + int expected[] = {INT_MAX, 3, 2, 1}; { - std::flat_set s(ks, vs, std::greater()); + std::flat_set s(ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_iter_iter() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const int arr[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arr[] = {1, 2, 3, INT_MAX}; + const int arrc[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arrc[] = {1, 2, 3, INT_MAX}; { std::flat_set m(std::begin(arr), std::end(arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::begin(arrc), std::end(arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.begin(), mo.end()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.cbegin(), mo.cend()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); - } - { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); + // This does not deduce to flat_set(InputIterator, InputIterator) + // But deduces to flat_set(initializer_list) + int source[3] = {1, 2, 3}; + std::flat_set s = {source, source + 3}; + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 2); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + int source[3] = {1, 2, 3}; std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); assert(s.size() == 3); } } void test_iter_iter_compare() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m(std::begin(arr), std::end(arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::begin(arrc), std::end(arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set mo; - std::flat_set m(mo.begin(), mo.end(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } - { - std::flat_set mo; - std::flat_set m(mo.cbegin(), mo.cend(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } + // const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m(std::begin(arr), std::end(arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.begin(), mo.end(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.cbegin(), mo.cend(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } } void test_initializer_list() { - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - { - std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - } - { - using M = std::flat_set; - M m; - std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - assert(s[m] == m); - } + // const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + // { + // std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // } + // { + // using M = std::flat_set; + // M m; + // std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // assert(s[m] == m); + // } } void test_initializer_list_compare() { - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } } void test_from_range() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; - { - std::flat_set s(std::from_range, r); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + // { + // std::flat_set s(std::from_range, r); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } void test_from_range_compare() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; - { - std::flat_set s(std::from_range, r, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + // { + // std::flat_set s(std::from_range, r, std::greater()); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } int main(int, char**) { @@ -335,7 +316,7 @@ int main(int, char**) { test_from_range(); test_from_range_compare(); - AssociativeContainerDeductionGuidesSfinaeAway>(); + AssociativeContainerDeductionGuidesSfinaeAway>(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp index 64b0bfcb383a720..292af96c61582fa 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -19,9 +19,10 @@ #include #include -#include "test_macros.h" #include "min_allocator.h" +#include "MoveOnly.h" #include "test_allocator.h" +#include "test_macros.h" struct DefaultCtableComp { explicit DefaultCtableComp() { default_constructed_ = true; } @@ -29,7 +30,12 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +void test() { { std::flat_set m; assert(m.empty()); @@ -60,6 +66,32 @@ int main(int, char**) { assert(m.key_comp().default_constructed_); } } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp deleted file mode 100644 index b4a3b6de205a31b..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set() -// noexcept( -// is_nothrow_default_constructible_v && -// is_nothrow_default_constructible_v); - -// This tests a conforming extension - -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -struct ThrowingCtorComp { - ThrowingCtorComp() noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -int main(int, char**) { -#if defined(_LIBCPP_VERSION) - { - using C = std::flat_set; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set, std::vector>>; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } -#endif // _LIBCPP_VERSION - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp index c0d315c0ce74b4b..fa1e2478af45997 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -27,7 +27,7 @@ struct ThrowingDtorComp { ~ThrowingDtorComp() noexcept(false) {} }; -int main(int, char**) { +void test() { { using C = std::flat_set; static_assert(std::is_nothrow_destructible_v); @@ -52,6 +52,10 @@ int main(int, char**) { C c; } #endif // _LIBCPP_VERSION +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp index cd2319e91f760d9..9aed5c88ee72680 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -35,7 +35,7 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -146,6 +146,10 @@ int main(int, char**) { M m({5, 2, 2, 3, 1, 3}, {}, a); assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp index 65eebc21a66c4cb..2d0b07c9155fdba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -29,7 +29,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -131,6 +131,10 @@ int main(int, char**) { LIBCPP_ASSERT(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp index 69b340ad09fe158..b2853844b986c6e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -25,7 +25,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; using A = test_allocator; @@ -79,5 +79,110 @@ int main(int, char**) { LIBCPP_ASSERT(m1.empty()); LIBCPP_ASSERT(m1.size() == 0); } +} + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +void test_move_noexcept() { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +} + +#if !defined(TEST_HAS_NO_EXCEPTIONS) +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +void test_move_exception() { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } +} +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + +int main(int, char**) { + test(); + test_move_noexcept(); +#if !defined(TEST_HAS_NO_EXCEPTIONS) + test_move_exception(); +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp index fc7f68d8c967ad2..489b6ff36324b3f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -53,7 +53,7 @@ int main(int, char**) { assert(m.size() == 3); auto keys = std::move(m).extract(); assert(keys.get_allocator() == A(3)); - assert(std::ranges::equal(keys, expected )); + assert(std::ranges::equal(keys, expected)); // The original flat_set is moved-from. assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); @@ -63,13 +63,17 @@ int main(int, char**) { } { // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, CopyOnlyVector>; + using M = std::flat_set, CopyOnlyVector>; M m1 = M({1, 2, 3}); M m2(std::move(m1), std::allocator{}); assert(m2.size() == 3); check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index b16dc38dd402859..e55a0516ed1bed2 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -22,11 +22,144 @@ #include "test_macros.h" #include "MoveOnly.h" +#include "../helpers.h" #include "../../../test_compare.h" #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +void test_move_assign_clears() { + // Preserves the class invariant for the moved-from flat_set. + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } +} + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +void test_move_assign_no_except() { + // This tests a conforming extension + + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } +} + +void test() { { using C = test_less; using A1 = test_allocator; @@ -64,6 +197,12 @@ int main(int, char**) { assert(ks.get_allocator() == A()); assert(mo.empty()); } +} + +int main(int, char**) { + test(); + test_move_assign_clears(); + test_move_assign_no_except(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp deleted file mode 100644 index 50817f4be8a8125..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&&); -// Preserves the class invariant for the moved-from flat_set. - -#include -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -struct MoveNegates { - int value_ = 0; - MoveNegates() = default; - MoveNegates(int v) : value_(v) {} - MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } - MoveNegates& operator=(MoveNegates&& rhs) { - value_ = rhs.value_; - rhs.value_ = -rhs.value_; - return *this; - } - ~MoveNegates() = default; - auto operator<=>(const MoveNegates&) const = default; -}; - -struct MoveClears { - int value_ = 0; - MoveClears() = default; - MoveClears(int v) : value_(v) {} - MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } - MoveClears& operator=(MoveClears&& rhs) { - value_ = rhs.value_; - rhs.value_ = 0; - return *this; - } - ~MoveClears() = default; - auto operator<=>(const MoveClears&) const = default; -}; - -int main(int, char**) { - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, std::vector>; - M m1 = M({1, 2, 3}); - M m2 = M({1, 2}); - m2 = std::move(m1); - assert(m2.size() == 3); - check_invariant(m1); - LIBCPP_ASSERT(m1.empty()); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp deleted file mode 100644 index 86f3568f0d67a6b..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&& c) -// noexcept( -// is_nothrow_move_assignable::value && -// is_nothrow_move_assignable::value && -// is_nothrow_copy_assignable::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include - -#include "MoveOnly.h" -#include "test_allocator.h" -#include "test_macros.h" - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -struct MoveThrowsComp { - MoveThrowsComp(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp(const MoveThrowsComp&) noexcept(true); - MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); - bool operator()(const auto&, const auto&) const; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - // Test with a comparator that throws on move-assignment. - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); - } - { - // Test with a container that throws on move-assignment. - using C = std::flat_set, std::pmr::vector>; - static_assert(!std::is_nothrow_move_assignable_v); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp deleted file mode 100644 index 17e4e40387606ce..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 -// UNSUPPORTED: no-exceptions - -// - -// flat_set(flat_set&& s); -// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. - -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -static int countdown = 0; - -struct EvilContainer : std::vector { - EvilContainer() = default; - EvilContainer(EvilContainer&& rhs) { - // Throw on move-construction. - if (--countdown == 0) { - rhs.insert(rhs.end(), 0); - rhs.insert(rhs.end(), 0); - throw 42; - } - } -}; - -int main(int, char**) { - { - using M = std::flat_set, EvilContainer>; - M mo = {1, 2, 3}; - countdown = 1; - try { - M m = std::move(mo); - assert(false); // not reached - } catch (int x) { - assert(x == 42); - } - // The source flat_set maintains its class invariant. - check_invariant(mo); - LIBCPP_ASSERT(mo.empty()); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp deleted file mode 100644 index 49d1151fd8a993c..000000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set(flat_set&&) -// noexcept(is_nothrow_move_constructible::value && -// is_nothrow_move_constructible::value && -// is_nothrow_copy_constructible::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -template -struct ThrowingMoveAllocator { - using value_type = T; - explicit ThrowingMoveAllocator() = default; - ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; - ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} - T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } - void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } - friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; -}; - -struct ThrowingMoveComp { - ThrowingMoveComp() = default; - ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} - ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - { - using C = std::flat_set, std::deque>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#if _LIBCPP_VERSION - { - // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators - using C = std::flat_set, std::deque>>; - static_assert(!std::is_nothrow_move_constructible_v>>); - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#endif // _LIBCPP_VERSION - { - // Comparator fails to be nothrow-move-constructible - using C = std::flat_set; - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp index 785718d2eed333f..1a4eafa8802918d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -28,7 +28,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // flat_set(const Allocator& a); using M = std::flat_set, std::pmr::vector>; @@ -317,6 +317,10 @@ int main(int, char**) { assert(vm[0].key_comp() == C(4)); assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp index bb9f99c228bfecc..bd7b5c12432e962 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -56,7 +56,7 @@ static_assert( !std:: is_constructible_v>, std::less, std::allocator>); -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -168,6 +168,10 @@ int main(int, char**) { assert(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp index 2d442d49667bd07..873ff32b62936a5 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -138,6 +138,10 @@ int main(int, char**) { assert(m2 == m); assert(std::move(m2).extract().get_allocator() == A(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp index 01956a78c7f48dd..a8dac35aefee81f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -33,10 +33,10 @@ template std::initializer_list il = {1, 2, 4, 5}; -const auto il1 = il; -const auto il2 = il; +void test() { + const auto il1 = il; + const auto il2 = il; -int main(int, char**) { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -145,6 +145,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp index b5229a84dd51333..b184ee9c3f5abae 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -28,7 +28,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -151,6 +151,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp index 134db83aef3cad2..806779bc7d16bc1 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -49,7 +49,7 @@ void test0( } template -void test() { +void test_one() { // Test all the plausible signatures for this predicate. auto is1 = [](typename S::const_reference v) { return v == 1; }; auto is2 = [](typename S::value_type v) { return v == 2; }; @@ -76,14 +76,18 @@ void test() { test0({1, 2, 3}, False, {1, 2, 3}, 0); } +void test() { + test_one>(); + test_one, std::vector>>>(); + test_one, std::vector>>>(); + test_one, std::deque>>>(); + test_one, std::deque>>>(); + test_one>(); + test_one>(); +} + int main(int, char**) { - test>(); - test, std::vector>>>(); - test, std::vector>>>(); - test, std::deque>>>(); - test, std::deque>>>(); - test>(); - test>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp index 6bbe1ad4f016705..37b4a40f0165cfe 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -65,7 +65,7 @@ struct ErasurePredicate { bool operator()(const auto& x) const { return (3 <= x && x <= 5); } }; -int main(int, char**) { +void test() { const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; { using M = std::flat_set; @@ -124,5 +124,10 @@ int main(int, char**) { } } } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp index c07297a141ad109..846bcff63d77365 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -30,7 +30,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -67,15 +67,15 @@ void test() { assert(i == m.begin()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::iterator ii1{}, ii2{}; C::iterator ii4 = ii1; C::const_iterator cii{}; @@ -88,6 +88,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp index 29441dcc57d40e4..3027cdd4076eea4 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using KI = typename KeyContainer::iterator; @@ -144,11 +144,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp index a16383cdcf53830..d1e4cef3de19e83 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include -int main(int, char**) { +void test() { { using M = std::flat_set, std::deque>; M m = {1, 2, 3, 4}; @@ -69,7 +69,7 @@ int main(int, char**) { } { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::reverse_iterator ii1{}, ii2{}; C::reverse_iterator ii4 = ii1; C::const_reverse_iterator cii{}; @@ -82,6 +82,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp index 221a13fa057577a..efa13a51c30bb35 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -38,7 +38,7 @@ static_assert(NoExceptClear, ThrowOnMoveContai #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -50,13 +50,17 @@ void test() { assert(m.size() == 0); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp index 95f7a3c5f5d34a2..79800e894afbfc9 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -28,7 +28,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -121,21 +121,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp index de855d5e5c30097..b3bd8adf0c35d8a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -27,7 +27,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = M::iterator; @@ -134,21 +134,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp index 386af04d26e9a2e..42562b84b4e22d7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -27,7 +27,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -106,16 +106,21 @@ void test() { assert(i8 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp index 7416977844e5df2..d402a7ba0285ec8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -77,15 +77,21 @@ void test() { assert(i4 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp index 25d4f4af19608b4..d81422d38718761 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template > -void test() { +void test_one() { using M = std::flat_set; auto make = [](std::initializer_list il) { @@ -70,22 +70,27 @@ void test() { assert(m.empty()); } -int main(int, char**) { - test>(); - test, std::greater<>>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one, std::greater<>>(); + test_one>(); + test_one>(); + test_one>>(); +} - { - auto erase_function = [](auto& m, auto key_arg) { - using Map = std::decay_t; - using Key = typename Map::key_type; - const Key key{key_arg}; - m.erase(key); - }; - test_erase_exception_guarantee(erase_function); - } +void test_exception() { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp index cbf7cac603806d7..c383844eb4973ec 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -50,7 +50,7 @@ struct HeterogeneousKey { }; template -void test_simple() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -86,11 +86,11 @@ void test_transparent_comparator() { assert(m == expected); } -int main(int, char**) { - test_simple>(); - test_simple>(); - test_simple>(); - test_simple>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_transparent_comparator>(); test_transparent_comparator>(); @@ -129,14 +129,20 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } - { - auto erase_transparent = [](auto& m, auto key_arg) { - using Set = std::decay_t; - using Key = typename Set::key_type; - m.erase(Transparent{key_arg}); - }; - test_erase_exception_guarantee(erase_transparent); - } +} + +void test_exception() { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp index c3bbffabb90a08f..dfa21a807f0254e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -33,7 +33,7 @@ static_assert(!CanExtract const&>); static_assert(!CanExtract const&&>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; M m = M({1, 2, 3}); @@ -45,11 +45,12 @@ void test() { LIBCPP_ASSERT(m.empty()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { // extracted object maintains invariant if the underlying container does not clear after move using M = std::flat_set, CopyOnlyVector>; @@ -59,7 +60,9 @@ int main(int, char**) { check_invariant(m); LIBCPP_ASSERT(m.empty()); } +} +void test_exception() { { #ifndef TEST_HAS_NO_EXCEPTIONS using KeyContainer = ThrowOnMoveContainer; @@ -79,5 +82,11 @@ int main(int, char**) { } #endif } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp index c0ddadc30069872..e0cb80f74462cd0 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -59,20 +59,25 @@ void test() { assert(*r.first == 3); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using value_type = typename std::decay_t::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(p); - }; - test_emplace_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp index 7381514a70eabbb..bf94fd9f5b11fda 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -23,12 +23,12 @@ #include "min_allocator.h" template -void test() { - using Key = typename KeyContainer::value_type; - using M = std::flat_set, KeyContainer>; - using V = typename M::value_type; +void test_one() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; - M m = {1,1,1,3,3,3}; + M m = {1, 1, 1, 3, 3, 3}; m.insert({ 4, 4, @@ -48,20 +48,26 @@ void test() { assert(*std::next(m.begin(), 3) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(il); - }; - test_insert_range_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index c343d53a62215a8..d6791853e0debdb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = typename M::iterator; @@ -55,13 +55,15 @@ void test() { assert(*r == 3); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; using value_type = typename FlatSet::value_type; @@ -69,6 +71,11 @@ int main(int, char**) { m.insert(m.begin(), p); }; test_emplace_exception_guarantee(insert_func); - } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp index d20a8ef8fdd92d8..8063686c960ed3f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; int ar1[] = { @@ -73,15 +73,22 @@ void test() { M expected2{0, 1, 2, 3, 4}; assert(m == expected2); } + +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp index 84b6c7fc1d34f62..d29de98e4d3ddbf 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -22,7 +22,7 @@ #include "test_macros.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -49,25 +49,30 @@ void test() { assert(*r == V(3)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(m.begin(), std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp index 536307252c64058..ed33827a7355c94 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -39,7 +39,7 @@ static_assert(!CanInsertRange*>>) static_assert(!CanInsertRange*>>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -75,31 +75,29 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { - // Items are forwarded correctly from the input range (P2767). + // Items are forwarded correctly from the input range. MoveOnly a[] = {3, 1, 4, 1, 5}; std::flat_set m; m.insert_range(a | std::views::as_rvalue); MoveOnly expected[] = {1, 3, 4, 5}; assert(std::ranges::equal(m, expected)); } - { - // The element type of the range doesn't need to be std::pair (P2767). - int pa[] = {3, 1, 4, 1, 5}; - std::deque> a(pa, pa + 5); - std::flat_set m; - m.insert_range(a); - int expected[] = {1, 3, 4, 5}; - assert(std::ranges::equal(m, expected)); - } - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; - test_insert_range_exception_guarantee(insert_func); - } +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp index 7d95f0521eb1f67..faf74142caff5c0 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -25,7 +25,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; using R = std::pair; @@ -57,24 +57,30 @@ void test() { assert(*r.first == V(3)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp index fa5bf86830daecd..38c36d1befaa7c4 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -38,21 +38,26 @@ void test() { assert(*std::next(m.begin(), 4) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(std::sorted_unique, il); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp index ef7b8391cee33c1..6258c4dbfdcbba3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -60,18 +60,23 @@ void test() { assert(m == expected2); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - m.insert(std::sorted_unique, newValues.begin(), newValues.end()); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp index 72d7261a1825477..d2ddf95aac2bb78 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -57,7 +57,7 @@ struct CompareCounter { }; template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -121,11 +121,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // no ambiguity between insert(pos, P&&) and insert(first, last) @@ -139,6 +139,9 @@ int main(int, char**) { ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); } +} + +void test_exception() { { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; @@ -165,5 +168,11 @@ int main(int, char**) { }; test_emplace_exception_guarantee(insert_func_iter); } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp index 49cb6eb6163c903..fca33bd41449e08 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -31,7 +31,7 @@ static_assert(CanReplace>); static_assert(!CanReplace&>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -43,30 +43,36 @@ void test() { assert(std::ranges::equal(m, expected_keys)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { #ifndef TEST_HAS_NO_EXCEPTIONS - using KeyContainer = ThrowOnMoveContainer; - using M = std::flat_set; + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; - M m; - m.emplace(1); - m.emplace(2); - try { - KeyContainer new_keys{3, 4}; - m.replace(std::move(new_keys)); - assert(false); - } catch (int) { - check_invariant(m); - // In libc++, we clear the map - LIBCPP_ASSERT(m.size() == 0); - } -#endif + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); } +#endif +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp index bc7baa67e52a599..ed13ba1ef3fea71 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -24,6 +24,8 @@ #include "test_macros.h" #include "../helpers.h" +#include "check_assertion.h" + // test noexcept template @@ -38,7 +40,7 @@ static_assert(NoExceptAdlSwap, ThrowOnMoveCont #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -84,11 +86,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp index b0b06a9499efc7a..1eac55d768ce0bc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -37,7 +37,7 @@ static_assert(NoExceptMemberSwap, ThrowOnMoveC #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -82,11 +82,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp index 971b5e1c338dd11..ba2c428c9e30e2b 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -21,7 +21,7 @@ #include "test_macros.h" -int main(int, char**) { +void test() { { using M = std::flat_set; using Comp = std::less; // the default @@ -67,6 +67,10 @@ int main(int, char**) { assert(vc(1, 2)); assert(!vc(2, 1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp index b14da66f611301e..e23683f6f289457 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp index 507560608952b01..0cdff44d11274fd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanContains); static_assert(!CanContains); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.contains(Transparent{"g"}) == false); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,5 +66,10 @@ int main(int, char**) { assert(b); assert(transparent_used); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp index 478f615358b6068..017f0fed3e9816d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using S = typename KeyContainer::size_type; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp index b591258f74399c8..0c5ce9d5799651a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanCount); static_assert(!CanCount); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.count(Transparent{"g"}) == 0); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,6 +66,10 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp index a088b7fee17d2ca..b55cbe2ac42a001 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -67,11 +67,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp index ede5d91e19b9fdd..97c4af19eaef377 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanEqualRange); static_assert(!CanEqualRange); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -77,11 +77,11 @@ void test() { test_not_found(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -92,6 +92,10 @@ int main(int, char**) { assert(p.first != p.second); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp index cf0dd2d1dd831c8..9ee8f043e1d9cdd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -25,7 +25,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m = {1, 2, 4, 5, 8}; @@ -43,11 +43,15 @@ void test() { assert(std::as_const(m).find(9) == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp index 730a57b0a6cb855..cc8ea12bcf4a6a3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanFind); static_assert(!CanFind); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -68,11 +68,11 @@ void test() { test_find(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -83,6 +83,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp index 093c32e537ed35f..1ceddb2f1c9d26e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -60,11 +60,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp index 18f9bc6dd329553..19991ca05fbc8a9 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanLowerBound); static_assert(!CanLowerBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,11 @@ void test() { test_lower_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -89,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp index ab34de851031756..f25896e12293977 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -61,11 +61,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp index 69ce2ae926a305e..c9b519d20321933 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanUpperBound); static_assert(!CanUpperBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,12 @@ void test() { test_upper_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { bool transparent_used = false; TransparentComparator c(transparent_used); @@ -88,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h index 9fff262d84234e9..2ee8b021337a06a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SUPPORT_flat_set_HELPERS_H -#define SUPPORT_flat_set_HELPERS_H +#ifndef SUPPORT_FLAT_SET_HELPERS_H +#define SUPPORT_FLAT_SET_HELPERS_H #include #include @@ -149,6 +149,19 @@ struct EmplaceUnsafeContainer : std::vector { throw 42; } + + template + auto insert_range(Args&&... args) + -> decltype(std::declval>().insert_range(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } }; template @@ -291,4 +304,4 @@ class Moveable { bool moved() const { return int_ == -1; } }; -#endif // SUPPORT_flat_set_HELPERS_H +#endif // SUPPORT_FLAT_SET_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp index c4a9810016536bd..faf746861df309f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -27,7 +27,10 @@ struct A { // Implement the operator< required in order to instantiate flat_set bool operator<(A const& L, A const& R) { return L.data < R.data; } +void test() { A a; } + int main(int, char**) { - A a; + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp index f6d08bb736d3004..3e7aecee77fdd88 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -31,7 +31,7 @@ #include "test_container_comparisons.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -69,11 +69,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { using C = std::flat_set; @@ -101,5 +101,10 @@ int main(int, char**) { assert(s1 != s2); assert((s1 <=> s2) == std::partial_ordering::unordered); } +} + +int main(int, char**) { + test(); + return 0; } >From 6fa4b5763cccee5d1631d9239c12f33d5c656956 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 14:08:01 +0000 Subject: [PATCH 3/7] review --- .../flat.set/assert.sorted_unique.pass.cpp | 226 ++++++++++++++++++ .../assign_initializer_list.pass.cpp | 6 +- .../flat.set.cons/move_assign.pass.cpp | 67 ++++-- 3 files changed, 280 insertions(+), 19 deletions(-) create mode 100644 libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp diff --git a/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp new file mode 100644 index 000000000000000..62903af7f4e477d --- /dev/null +++ b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp @@ -0,0 +1,226 @@ +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: libcpp-hardening-mode=none +// REQUIRES: libcpp-hardening-mode=debug +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// + +// flat_set(container_type , const key_compare& __comp = key_compare()) +// flat_set(const container_type& , const _Allocator& ) +// flat_set(const container_type& , const key_compare&, const _Allocator& ) +// void replace(container_type&& ) +// + +#include +#include +#include +#include +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + using M = std::flat_set; + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{1, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{2, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7e948d7c5fe976b..ad49b621490366d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -30,14 +30,16 @@ void test_one() { { M m = {8, 10}; assert(m.size() == 2); - m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + std::same_as decltype(auto) r = m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + assert(&r == &m); int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); } { M m = {10, 8}; assert(m.size() == 2); - m = {3}; + std::same_as decltype(auto) r = m = {3}; + assert(&r == &m); int expected[] = {3}; assert(std::ranges::equal(m, expected)); } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index e55a0516ed1bed2..0e0ab0aa135f9ff 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -55,6 +55,19 @@ struct MoveClears { auto operator<=>(const MoveClears&) const = default; }; +#if !defined(TEST_HAS_NO_EXCEPTIONS) +struct MoveAssignThrows : std::vector { + using std::vector::vector; + MoveAssignThrows& operator=(MoveAssignThrows&& other) { + push_back(0); + push_back(0); + other.push_back(0); + other.push_back(0); + throw 42; + } +}; +#endif // TEST_HAS_NO_EXCEPTIONS + void test_move_assign_clears() { // Preserves the class invariant for the moved-from flat_set. { @@ -101,6 +114,23 @@ void test_move_assign_clears() { check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +#if !defined(TEST_HAS_NO_EXCEPTIONS) + { + using M = std::flat_set, MoveAssignThrows>; + M m1 = {1, 2, 3}; + M m2 = {1, 2}; + try { + m2 = std::move(m1); + assert(false); + } catch (int e) { + assert(e == 42); + } + check_invariant(m1); + check_invariant(m2); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m2.empty()); + } +#endif // TEST_HAS_NO_EXCEPTIONS } struct MoveSensitiveComp { @@ -161,12 +191,13 @@ void test_move_assign_no_except() { void test() { { - using C = test_less; - using A1 = test_allocator; - using M = std::flat_set>; - M mo = M({1, 2, 3}, C(5), A1(7)); - M m = M({}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{1, 2, 3})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -174,12 +205,13 @@ void test() { assert(mo.empty()); } { - using C = test_less; - using A1 = other_allocator; - using M = std::flat_set>; - M mo = M({4, 5}, C(5), A1(7)); - M m = M({1, 2, 3, 4}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{4, 5})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -187,11 +219,12 @@ void test() { assert(mo.empty()); } { - using A = min_allocator; - using M = std::flat_set, std::vector>; - M mo = M({5, 4, 3}, A()); - M m = M({4, 3, 2, 1}, A()); - m = std::move(mo); + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{5, 4, 3})); auto ks = std::move(m).extract(); assert(ks.get_allocator() == A()); >From c65a37ea8012b92dc5575be91a1a18851a8caeaa Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 16:23:56 +0000 Subject: [PATCH 4/7] clang-format --- .../flat.set/flat.set.capacity/max_size.pass.cpp | 1 - .../flat.set.modifiers/insert_iter_cv.pass.cpp | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index 0489d8862579119..dde1f7092e5b18c 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -25,7 +25,6 @@ #include "test_macros.h" void test() { - { using A1 = limited_allocator; using C = std::flat_set, std::vector>; diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index d6791853e0debdb..76b4d5f0eb7cc6a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -56,7 +56,6 @@ void test_one() { } void test() { - test_one>(); test_one>(); test_one>(); @@ -64,13 +63,13 @@ void test() { } void test_exception() { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(m.begin(), p); - }; - test_emplace_exception_guarantee(insert_func); + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); } int main(int, char**) { >From 61147247cfcf3fd4623587bddaa07a2c4783d2b6 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 16:59:41 +0000 Subject: [PATCH 5/7] CI --- libcxx/docs/ReleaseNotes/21.rst | 1 + libcxx/docs/Status/Cxx23Papers.csv | 2 +- libcxx/modules/std.compat.cppm.in | 3 - libcxx/modules/std.cppm.in | 4 +- libcxx/modules/std/flat_set.inc | 4 +- .../test/libcxx/transitive_includes/cxx03.csv | 8 ++ .../test/libcxx/transitive_includes/cxx11.csv | 8 ++ .../test/libcxx/transitive_includes/cxx14.csv | 8 ++ .../test/libcxx/transitive_includes/cxx17.csv | 8 ++ .../test/libcxx/transitive_includes/cxx20.csv | 8 ++ .../test/libcxx/transitive_includes/cxx23.csv | 15 +++- .../test/libcxx/transitive_includes/cxx26.csv | 14 ++++ .../flat_set.version.compile.pass.cpp | 80 +++++++++++++++++++ libcxx/utils/libcxx/header_information.py | 2 +- 14 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad39423..0c1029f50a6fe7d 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -39,6 +39,7 @@ Implemented Papers ------------------ - N4258: Cleaning-up noexcept in the Library (`Github `__) +- P1222R4: A Standard ``flat_set`` is partially implemented and ``flat_set`` is provided (`Github `__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 264c5417a5c28be..bcd9c5c43a9c695 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -54,7 +54,7 @@ "`P0009R18 `__","mdspan: A Non-Owning Multidimensional Array Reference","2022-07 (Virtual)","|Complete|","18","" "`P0429R9 `__","A Standard ``flat_map``","2022-07 (Virtual)","|Complete|","20","" "`P1169R4 `__","``static operator()``","2022-07 (Virtual)","|Complete|","16","" -"`P1222R4 `__","A Standard ``flat_set``","2022-07 (Virtual)","","","" +"`P1222R4 `__","A Standard ``flat_set``","2022-07 (Virtual)","|In progress|","","" "`P1223R5 `__","``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()``","2022-07 (Virtual)","|Complete|","19","" "`P1467R9 `__","Extended ``floating-point`` types and standard names","2022-07 (Virtual)","","","" "`P1642R11 `__","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","2022-07 (Virtual)","","","" diff --git a/libcxx/modules/std.compat.cppm.in b/libcxx/modules/std.compat.cppm.in index 5cea1b75bfc1706..95931447ccdc64e 100644 --- a/libcxx/modules/std.compat.cppm.in +++ b/libcxx/modules/std.compat.cppm.in @@ -53,9 +53,6 @@ module; # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in index b9d00df70658d87..5c523691bff4e2a 100644 --- a/libcxx/modules/std.cppm.in +++ b/libcxx/modules/std.cppm.in @@ -65,6 +65,7 @@ module; #include #include #include +#include #include #include #if _LIBCPP_HAS_LOCALIZATION @@ -162,9 +163,6 @@ module; # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std/flat_set.inc b/libcxx/modules/std/flat_set.inc index a86cc1eae02a62f..3f2c6e09a0ebe48 100644 --- a/libcxx/modules/std/flat_set.inc +++ b/libcxx/modules/std/flat_set.inc @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// export namespace std { -#if 0 +#if _LIBCPP_STD_VER >= 23 // [flat.set], class template flat_­set using std::flat_set; @@ -19,7 +19,9 @@ export namespace std { // [flat.set.erasure], erasure for flat_­set using std::erase_if; +#endif // _LIBCPP_STD_VER >= 23 +#if 0 // [flat.multiset], class template flat_­multiset using std::flat_multiset; diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv index ec5db90597d9271..c0031543e47bce8 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -683,6 +683,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv index ec5db90597d9271..c0031543e47bce8 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -683,6 +683,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv index 95024df0590b846..c2eb5b44e8d7a76 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -701,6 +701,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv index a3518f7f62ecb96..332cb62f35b5f45 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -709,6 +709,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv index 6de951392794719..55c79acff5a8f9d 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -705,6 +705,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv index 17972b84537436c..7da07a8b3749b2b 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -345,6 +345,20 @@ flat_map optional flat_map stdexcept flat_map tuple flat_map version +flat_set cctype +flat_set climits +flat_set compare +flat_set cstdint +flat_set cstring +flat_set cwchar +flat_set cwctype +flat_set initializer_list +flat_set limits +flat_set optional +flat_set stdexcept +flat_set tuple +flat_set type_traits +flat_set version format array format cctype format cerrno @@ -556,7 +570,6 @@ istream ios istream iosfwd istream limits istream locale - istream ratio istream stdexcept istream streambuf diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv index 00ab78e61a4576f..4c2782a4ce5cf98 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -345,6 +345,20 @@ flat_map optional flat_map stdexcept flat_map tuple flat_map version +flat_set cctype +flat_set climits +flat_set compare +flat_set cstdint +flat_set cstring +flat_set cwchar +flat_set cwctype +flat_set initializer_list +flat_set limits +flat_set optional +flat_set stdexcept +flat_set tuple +flat_set type_traits +flat_set version format array format cctype format cerrno diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp new file mode 100644 index 000000000000000..f9d0b0a6b4e4f66 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. +// +// clang-format off + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_flat_set 202207L [C++23] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should be defined in c++23" +# endif +# if __cpp_lib_flat_set != 202207L +# error "__cpp_lib_flat_set should have the value 202207L in c++23" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#elif TEST_STD_VER > 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should be defined in c++26" +# endif +# if __cpp_lib_flat_set != 202207L +# error "__cpp_lib_flat_set should have the value 202207L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#endif // TEST_STD_VER > 23 + diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py index 9a723b61524cd55..9811b42d510ca3f 100644 --- a/libcxx/utils/libcxx/header_information.py +++ b/libcxx/utils/libcxx/header_information.py @@ -164,7 +164,6 @@ def __hash__(self) -> int: # modules will fail to build if a header is added but this list is not updated. headers_not_available = list(map(Header, [ "debugging", - "flat_set", "generator", "hazard_pointer", "inplace_vector", @@ -261,6 +260,7 @@ def __hash__(self) -> int: "deque": ["compare", "initializer_list"], "filesystem": ["compare"], "flat_map": ["compare", "initializer_list"], + "flat_set": ["compare", "initializer_list"], "forward_list": ["compare", "initializer_list"], "ios": ["iosfwd"], "iostream": ["ios", "istream", "ostream", "streambuf"], >From a7583dad7798ec3f4259a2bcd4e851a85c7e04d6 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 18:05:17 +0000 Subject: [PATCH 6/7] deduction --- .../flat.set.cons/deduct.compile.pass.cpp | 14 +- .../flat.set/flat.set.cons/deduct.pass.cpp | 239 +++++++++--------- 2 files changed, 121 insertions(+), 132 deletions(-) diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp index 5db8c4ca7224665..1161fe6e61c78eb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp @@ -23,27 +23,21 @@ struct NotAnAllocator { }; template -concept CanDeductFlatSet = requires { std::flat_set{std::declval()...}; }; +concept CanDeductFlatSet = requires { std::flat_set(std::declval()...); }; -static_assert(CanDeductFlatSet, std::vector>); +static_assert(CanDeductFlatSet>); // cannot deduce Key and T from nothing static_assert(!CanDeductFlatSet<>); -// cannot deduce Key and T from just (KeyContainer), even if it's a container of pairs -static_assert(!CanDeductFlatSet>>); - -// cannot deduce Key and T from just (KeyContainer, Allocator) -static_assert(!CanDeductFlatSet, std::allocator>>); - // cannot deduce Key and T from just (Compare) static_assert(!CanDeductFlatSet>); // cannot deduce Key and T from just (Compare, Allocator) -static_assert(!CanDeductFlatSet, std::allocator>); +static_assert(!CanDeductFlatSet, std::allocator>); // cannot deduce Key and T from just (Allocator) -static_assert(!CanDeductFlatSet>); +static_assert(!CanDeductFlatSet>); // cannot convert from some arbitrary unrelated type static_assert(!CanDeductFlatSet); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp index 607fe0d1a9713a9..491c77d3737af18 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -116,8 +116,8 @@ void test_containers_compare() { } void test_iter_iter() { - const int arr[] = {1, 2, 1, INT_MAX, 3}; - const int sorted_arr[] = {1, 2, 3, INT_MAX}; + int arr[] = {1, 2, 1, INT_MAX, 3}; + int sorted_arr[] = {1, 2, 3, INT_MAX}; const int arrc[] = {1, 2, 1, INT_MAX, 3}; const int sorted_arrc[] = {1, 2, 3, INT_MAX}; { @@ -154,6 +154,12 @@ void test_iter_iter() { std::flat_set m(mo.cbegin(), mo.cend()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } + { + int source[3] = {1, 2, 3}; + std::flat_set s(source, source + 3); + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } { // This does not deduce to flat_set(InputIterator, InputIterator) // But deduces to flat_set(initializer_list) @@ -171,140 +177,125 @@ void test_iter_iter() { } void test_iter_iter_compare() { - // const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - // const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // using C = std::greater; - // { - // std::flat_set m(std::begin(arr), std::end(arr), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::begin(arrc), std::end(arrc), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set mo; - // std::flat_set m(mo.begin(), mo.end(), C()); - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // } - // { - // std::flat_set mo; - // std::flat_set m(mo.cbegin(), mo.cend(), C()); - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // } + int arr[] = {1, 2, 1, INT_MAX, 3}; + int sorted_arr[] = {INT_MAX, 3, 2, 1}; + const int arrc[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arrc[] = {INT_MAX, 3, 2, 1}; + using C = std::greater; + { + std::flat_set m(std::begin(arr), std::end(arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } } void test_initializer_list() { - // const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - // { - // std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) - // ASSERT_SAME_TYPE(decltype(s), std::flat_set); - // assert(s.size() == 1); - // } - // { - // using M = std::flat_set; - // M m; - // std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) - // ASSERT_SAME_TYPE(decltype(s), std::flat_set); - // assert(s.size() == 1); - // assert(s[m] == m); - // } + const int sorted_arr[] = {1, 2, 3, INT_MAX}; + { + std::flat_set m{1, 2, 1, INT_MAX, 3}; + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {1, 2, 3, INT_MAX}); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set s = {1}; + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } + { + using M = std::flat_set; + M m; + std::flat_set s{m, m}; // flat_set(initializer_list) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } } void test_initializer_list_compare() { - // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // using C = std::greater; - // { - // std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } + const int sorted_arr[] = {INT_MAX, 3, 2, 1}; + using C = std::greater; + { + std::flat_set m({1, 2, 1, INT_MAX, 3}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {INT_MAX, 3, 2, 1}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } } void test_from_range() { - // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - // const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; - // { - // std::flat_set s(std::from_range, r); - // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - // assert(std::ranges::equal(s, expected)); - // } - // { - // std::flat_set s(std::from_range, r, test_allocator(0, 42)); - // ASSERT_SAME_TYPE( - // decltype(s), - // std::flat_set, - // std::vector>, - // std::vector>>); - // assert(std::ranges::equal(s, expected)); - // assert(s.keys().get_allocator().get_id() == 42); - // assert(s.values().get_allocator().get_id() == 42); - // } + std::list r = {1, 2, 1, INT_MAX, 3}; + const int expected[] = {1, 2, 3, INT_MAX}; + { + std::flat_set s(std::from_range, r); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, test_allocator(0, 42)); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(std::move(s).extract().get_allocator().get_id() == 42); + } } void test_from_range_compare() { - // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - // const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; - // { - // std::flat_set s(std::from_range, r, std::greater()); - // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - // assert(std::ranges::equal(s, expected)); - // } - // { - // std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); - // ASSERT_SAME_TYPE( - // decltype(s), - // std::flat_set, - // std::vector>, - // std::vector>>); - // assert(std::ranges::equal(s, expected)); - // assert(s.keys().get_allocator().get_id() == 42); - // assert(s.values().get_allocator().get_id() == 42); - // } + std::list r = {1, 2, 1, INT_MAX, 3}; + const int expected[] = {INT_MAX, 3, 2, 1}; + { + std::flat_set s(std::from_range, r, std::greater()); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(std::move(s).extract().get_allocator().get_id() == 42); + } } -int main(int, char**) { +void test() { // Each test function also tests the sorted_unique-prefixed and allocator-suffixed overloads. test_copy(); test_containers(); @@ -317,6 +308,10 @@ int main(int, char**) { test_from_range_compare(); AssociativeContainerDeductionGuidesSfinaeAway>(); +} + +int main(int, char**) { + test(); return 0; } >From 8e266130512ef5788ea87361fcd0b194b0ae850e Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 18:45:39 +0000 Subject: [PATCH 7/7] CI --- libcxx/include/__flat_set/flat_set.h | 4 ++-- libcxx/include/module.modulemap | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index 37e4c9f7c686b00..30fe1343e63ee9d 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -838,8 +838,8 @@ template _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); - auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { - return static_cast(__pred(e)); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& __e) -> bool { + return static_cast(__pred(__e)); }); auto __res = __flat_set.__keys_.end() - __it; __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index abc351d5923963d..261362baeec5b8c 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1268,6 +1268,7 @@ module std [system] { header "__flat_set/flat_set.h" export std.vector.vector export std.vector.fwd + export std.flat_map.sorted_unique } header "flat_set" From libcxx-commits at lists.llvm.org Sun Feb 2 10:50:40 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Sun, 02 Feb 2025 10:50:40 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <679fbe80.050a0220.2e255f.470a@mx.google.com> ================ @@ -447,10 +449,41 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) { } # endif +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional> __try_constant_folding_format( + basic_string_view<_CharT> __fmt, + basic_format_args>, _CharT>> __args) { + // [[gnu::pure]] is added to ensure that the compiler always knows that this call can be eliminated. + if (bool __is_identity = + [&] [[__gnu__::__pure__]] { return std::ranges::find_first_of(__fmt, array{'{', '}'}) == __fmt.end(); }(); ---------------- mordante wrote: In format we typically do the latter, so it reads very odd to do things differently here. I'm even a bit surprised this compiles since you want to compare `wchar_t` against `char`. https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Sun Feb 2 10:50:41 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Sun, 02 Feb 2025 10:50:41 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <679fbe81.630a0220.260399.3eff@mx.google.com> ================ @@ -447,10 +449,41 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) { } # endif +template ---------------- mordante wrote: I find the code very hard to read and hard to understand what it tries to do. So I really like some comment in the code explaining what happens, that also would help me to review the code. https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Sun Feb 2 11:15:33 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Sun, 02 Feb 2025 11:15:33 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] implement std::flat_set (PR #125241) In-Reply-To: Message-ID: <679fc455.050a0220.126770.dc52@mx.google.com> https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/125241 >From f315d757119fde3cf298c18914a33e9cf76f27d1 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Fri, 31 Jan 2025 15:53:09 +0000 Subject: [PATCH 1/8] [libc++] implement std::flat_set --- libcxx/include/CMakeLists.txt | 2 + libcxx/include/__flat_set/flat_set.h | 853 ++++++++++++++++++ libcxx/include/flat_set | 59 ++ libcxx/include/module.modulemap | 11 + .../flat.set/flat.set.capacity/empty.pass.cpp | 48 + .../flat.set.capacity/empty.verify.cpp | 20 + .../flat.set.capacity/max_size.pass.cpp | 63 ++ .../flat.set/flat.set.capacity/size.pass.cpp | 66 ++ .../flat.set/flat.set.cons/alloc.pass.cpp | 60 ++ .../assign_initializer_list.pass.cpp | 56 ++ .../flat.set/flat.set.cons/compare.pass.cpp | 83 ++ .../flat.set.cons/containers.pass.cpp | 158 ++++ .../flat.set/flat.set.cons/copy.pass.cpp | 64 ++ .../flat.set.cons/copy_alloc.pass.cpp | 63 ++ .../copy_assign.addressof.compile.pass.cpp | 30 + .../flat.set.cons/copy_assign.pass.cpp | 85 ++ .../flat.set.cons/deduct.compile.pass.cpp | 49 + .../flat.set/flat.set.cons/deduct.pass.cpp | 341 +++++++ .../flat.set.cons/deduct_pmr.pass.cpp | 94 ++ .../flat.set/flat.set.cons/default.pass.cpp | 65 ++ .../flat.set.cons/default_noexcept.pass.cpp | 58 ++ .../flat.set.cons/dtor_noexcept.pass.cpp | 57 ++ .../flat.set.cons/initializer_list.pass.cpp | 151 ++++ .../flat.set/flat.set.cons/iter_iter.pass.cpp | 136 +++ .../flat.set/flat.set.cons/move.pass.cpp | 83 ++ .../flat.set.cons/move_alloc.pass.cpp | 75 ++ .../flat.set.cons/move_assign.pass.cpp | 69 ++ .../flat.set.cons/move_assign_clears.pass.cpp | 101 +++ .../move_assign_noexcept.pass.cpp | 85 ++ .../flat.set.cons/move_exceptions.pass.cpp | 58 ++ .../flat.set.cons/move_noexcept.pass.cpp | 94 ++ .../flat.set/flat.set.cons/pmr.pass.cpp | 322 +++++++ .../flat.set/flat.set.cons/range.pass.cpp | 173 ++++ .../flat.set.cons/sorted_container.pass.cpp | 143 +++ .../sorted_initializer_list.pass.cpp | 150 +++ .../flat.set.cons/sorted_iter_iter.pass.cpp | 156 ++++ .../flat.set.erasure/erase_if.pass.cpp | 89 ++ .../erase_if_exceptions.pass.cpp | 128 +++ .../flat.set.iterators/iterator.pass.cpp | 93 ++ .../iterator_comparison.pass.cpp | 154 ++++ ...rator_concept_conformance.compile.pass.cpp | 77 ++ ...range_concept_conformance.compile.pass.cpp | 52 ++ .../reverse_iterator.pass.cpp | 87 ++ .../flat.set.modifiers/clear.pass.cpp | 62 ++ .../flat.set.modifiers/emplace.pass.cpp | 141 +++ .../flat.set.modifiers/emplace_hint.pass.cpp | 154 ++++ .../flat.set.modifiers/erase_iter.pass.cpp | 121 +++ .../erase_iter_iter.pass.cpp | 91 ++ .../flat.set.modifiers/erase_key.pass.cpp | 91 ++ .../erase_key_transparent.pass.cpp | 142 +++ .../flat.set.modifiers/extract.pass.cpp | 83 ++ .../flat.set.modifiers/insert_cv.pass.cpp | 78 ++ .../insert_initializer_list.pass.cpp | 67 ++ .../insert_iter_cv.pass.cpp | 74 ++ .../insert_iter_iter.pass.cpp | 87 ++ .../insert_iter_rv.pass.cpp | 73 ++ .../flat.set.modifiers/insert_range.pass.cpp | 105 +++ .../flat.set.modifiers/insert_rv.pass.cpp | 80 ++ .../insert_sorted_initializer_list.pass.cpp | 58 ++ .../insert_sorted_iter_iter.pass.cpp | 77 ++ .../insert_transparent.pass.cpp | 169 ++++ .../flat.set.modifiers/replace.pass.cpp | 72 ++ .../swap_exception.pass.cpp | 61 ++ .../flat.set.modifiers/swap_free.pass.cpp | 94 ++ .../flat.set.modifiers/swap_member.pass.cpp | 92 ++ .../flat.set/flat.set.observers/comp.pass.cpp | 72 ++ .../flat.set.operations/contains.pass.cpp | 69 ++ .../contains_transparent.pass.cpp | 70 ++ .../flat.set.operations/count.pass.cpp | 69 ++ .../count_transparent.pass.cpp | 71 ++ .../flat.set.operations/equal_range.pass.cpp | 77 ++ .../equal_range_transparent.pass.cpp | 97 ++ .../flat.set.operations/find.pass.cpp | 53 ++ .../find_transparent.pass.cpp | 88 ++ .../flat.set.operations/lower_bound.pass.cpp | 70 ++ .../lower_bound_transparent.pass.cpp | 94 ++ .../flat.set.operations/upper_bound.pass.cpp | 71 ++ .../upper_bound_transparent.pass.cpp | 93 ++ .../container.adaptors/flat.set/helpers.h | 294 ++++++ .../flat.set/incomplete_type.pass.cpp | 33 + .../flat.set/op_compare.pass.cpp | 105 +++ .../flat.set/types.compile.pass.cpp | 94 ++ 82 files changed, 8453 insertions(+) create mode 100644 libcxx/include/__flat_set/flat_set.h create mode 100644 libcxx/include/flat_set create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/helpers.h create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8dac823503d73f..75acf9f7899ff6 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -367,6 +367,7 @@ set(files __flat_map/sorted_equivalent.h __flat_map/sorted_unique.h __flat_map/utils.h + __flat_set/flat_set.h __format/buffer.h __format/concepts.h __format/container_adaptor.h @@ -986,6 +987,7 @@ set(files fenv.h filesystem flat_map + flat_set float.h format forward_list diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h new file mode 100644 index 00000000000000..c920632c453bf5 --- /dev/null +++ b/libcxx/include/__flat_set/flat_set.h @@ -0,0 +1,853 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FLAT_set_FLAT_SET_H +#define _LIBCPP___FLAT_set_FLAT_SET_H + +#include <__algorithm/lexicographical_compare_three_way.h> +#include <__algorithm/min.h> +#include <__algorithm/ranges_adjacent_find.h> +#include <__algorithm/ranges_equal.h> +#include <__algorithm/ranges_inplace_merge.h> +#include <__algorithm/ranges_lower_bound.h> +#include <__algorithm/ranges_partition_point.h> +#include <__algorithm/ranges_sort.h> +#include <__algorithm/ranges_unique.h> +#include <__algorithm/ranges_upper_bound.h> +#include <__algorithm/remove_if.h> +#include <__assert> +#include <__compare/synth_three_way.h> +#include <__concepts/swappable.h> +#include <__config> +#include <__cstddef/byte.h> +#include <__cstddef/ptrdiff_t.h> +#include <__flat_map/sorted_unique.h> +#include <__functional/invoke.h> +#include <__functional/is_transparent.h> +#include <__functional/operations.h> +#include <__fwd/vector.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/ranges_iterator_traits.h> +#include <__iterator/reverse_iterator.h> +#include <__memory/allocator_traits.h> +#include <__memory/uses_allocator.h> +#include <__memory/uses_allocator_construction.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/container_compatible_range.h> +#include <__ranges/drop_view.h> +#include <__ranges/from_range.h> +#include <__ranges/ref_view.h> +#include <__ranges/size.h> +#include <__ranges/subrange.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/container_traits.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_allocator.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_same.h> +#include <__utility/exception_guard.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include <__utility/scope_guard.h> +#include <__vector/vector.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template , class _KeyContainer = vector<_Key>> +class flat_set { + template + friend class flat_set; + + static_assert(is_same_v<_Key, typename _KeyContainer::value_type>); + static_assert(!is_same_v<_KeyContainer, std::vector>, "vector is not a sequence container"); + +public: + // types + using key_type = _Key; + using value_type = _Key; + using key_compare = __type_identity_t<_Compare>; + using value_compare = _Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename _KeyContainer::size_type; + using difference_type = typename _KeyContainer::difference_type; + using iterator = typename _KeyContainer::const_iterator; + using const_iterator = iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using container_type = _KeyContainer; + +private: + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = + uses_allocator::value; + + _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; + +public: + // [flat.set.cons], construct/copy/destroy + _LIBCPP_HIDE_FROM_ABI + flat_set() noexcept(is_nothrow_default_constructible_v<_KeyContainer> && is_nothrow_default_constructible_v<_Compare>) + : __keys_(), __compare_() {} + + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other) noexcept( + is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : __keys_(std::move(__other.__keys_)), __compare_(std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + // gcc does not like the `throw` keyword in a conditionally noexcept function + if constexpr (!(is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>)) { + throw; + } +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const key_compare& __comp) : __keys_(), __compare_(__comp) {} + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + __sort_and_unique(); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(), __compare_(__comp) { + insert(__first, __last); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(__first, __last), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg) + : flat_set(from_range, std::forward<_Range>(__rg), key_compare()) {} + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp) : flat_set(__comp) { + insert_range(std::forward<_Range>(__rg)); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(__il.begin(), __il.end(), __comp) {} + + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : flat_set(__ctor_uses_allocator_tag{}, __alloc, std::move(__other.__keys_), std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + throw; +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(sorted_unique, __first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, + _InputIterator __first, + _InputIterator __last, + const key_compare& __comp, + const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(sorted_unique, __first, __last); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert_range(std::forward<_Range>(__rg)); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert_range(std::forward<_Range>(__rg)); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(initializer_list __il) { + clear(); + insert(__il); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(flat_set&& __other) noexcept( + is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_Compare>) { + // No matter what happens, we always want to clear the other container before returning + // since we moved from it + auto __clear_other_guard = std::__make_scope_guard([&]() noexcept { __other.clear() /* noexcept */; }); + { + // If an exception is thrown, we have no choice but to clear *this to preserve invariants + auto __on_exception = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__other.__keys_); + __compare_ = std::move(__other.__compare_); + __on_exception.__complete(); + } + return *this; + } + + // iterators + _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + + _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return begin(); } + _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return end(); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + // [flat.set.capacity], capacity + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __keys_.empty(); } + + _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __keys_.size(); } + + _LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept { return __keys_.max_size(); } + + // [flat.set.modifiers], modifiers + template + _LIBCPP_HIDE_FROM_ABI pair emplace(_Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __try_emplace(std::forward<_Args>(__args)...); + } else { + return __try_emplace(_Key(std::forward<_Args>(__args)...)); + } + } + + template + _LIBCPP_HIDE_FROM_ABI iterator emplace_hint(const_iterator __hint, _Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __emplace_hint(std::move(__hint), std::forward<_Args>(__args)...); + } else { + return __emplace_hint(std::move(__hint), _Key(std::forward<_Args>(__args)...)); + } + } + + _LIBCPP_HIDE_FROM_ABI pair insert(const value_type& __x) { return emplace(__x); } + + _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { + return emplace(std::forward<_Kp>(__x)); + } + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, const value_type& __x) { + return emplace_hint(__hint, __x); + } + + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, value_type&& __x) { + return emplace_hint(__hint, std::move(__x)); + } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { + return emplace_hint(__hint, std::forward<_Kp>(__x)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, _InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { + if constexpr (ranges::sized_range<_Range>) { + __reserve(ranges::size(__range)); + } + + __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + } + + _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } + + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, initializer_list __il) { + insert(sorted_unique, __il.begin(), __il.end()); + } + + _LIBCPP_HIDE_FROM_ABI container_type extract() && { + auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; }); + auto __ret = std::move(__keys_); + return __ret; + } + + _LIBCPP_HIDE_FROM_ABI void replace(container_type&& __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys), "Either the key container is not sorted or it contains duplicates"); + auto __guard = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__keys); + __guard.__complete(); + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __position) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_iter = __keys_.erase(__position); + __on_failure.__complete(); + return __key_iter; + } + + // The following overload is the same as the iterator overload + // iterator erase(const_iterator __position); + + _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __x) { + auto __iter = find(__x); + if (__iter != end()) { + erase(__iter); + return 1; + } + return 0; + } + + template + requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + !is_convertible_v<_Kp &&, const_iterator>) + _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { + auto [__first, __last] = equal_range(__x); + auto __res = __last - __first; + erase(__first, __last); + return __res; + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_it = __keys_.erase(__first, __last); + __on_failure.__complete(); + return __key_it; + } + + _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __y) noexcept { + // warning: The spec has unconditional noexcept, which means that + // if any of the following functions throw an exception, + // std::terminate will be called. + // This is discussed in P2767, which hasn't been voted on yet. + ranges::swap(__compare_, __y.__compare_); + ranges::swap(__keys_, __y.__keys_); + } + + _LIBCPP_HIDE_FROM_ABI void clear() noexcept { __keys_.clear(); } + + // observers + _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __compare_; } + _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __compare_; } + + // set operations + _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __x) { return __find_impl(*this, __x); } + + _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { + return __find_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { + return __find_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { + return contains(__x) ? 1 : 0; + } + + _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { + return find(__x) != end(); + } + + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) { + return __equal_range_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) const { + return __equal_range_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { + return __equal_range_impl(*this, __x); + } + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { + return __equal_range_impl(*this, __x); + } + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const flat_set& __x, const flat_set& __y) { + return ranges::equal(__x, __y); + } + + friend _LIBCPP_HIDE_FROM_ABI auto operator<=>(const flat_set& __x, const flat_set& __y) { + return std::lexicographical_compare_three_way( + __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); + } + + friend _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __x, flat_set& __y) noexcept { __x.swap(__y); } + +private: + struct __ctor_uses_allocator_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_tag() = default; + }; + struct __ctor_uses_allocator_empty_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_empty_tag() = default; + }; + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), + __compare_(std::forward<_CompArg>(__comp)...) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc)), + __compare_(std::forward<_CompArg>(__comp)...) {} + + _LIBCPP_HIDE_FROM_ABI bool __is_sorted_and_unique(auto&& __key_container) const { + auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) { return !__compare_(__x, __y); }; + return ranges::adjacent_find(__key_container, __greater_or_equal_to) == ranges::end(__key_container); + } + + // This function is only used in constructors. So there is not exception handling in this function. + // If the function exits via an exception, there will be no flat_set object constructed, thus, there + // is no invariant state to preserve + _LIBCPP_HIDE_FROM_ABI void __sort_and_unique() { + ranges::sort(__keys_, __compare_); + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } else { + for (; __first != __last; ++__first) { + __keys_.insert(__keys_.end(), *__first); + } + } + if (size() != __old_size) { + if constexpr (!_WasSorted) { + ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); + } else { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__is_sorted_and_unique(__keys_ | ranges::views::drop(__old_size)), + "Either the key container is not sorted or it contains duplicates"); + } + ranges::inplace_merge(__keys_.begin(), __keys_.begin() + __old_size, __keys_.end(), __compare_); + + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + __on_failure.__complete(); + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __find_impl(_Self&& __self, const _Kp& __key) { + auto __it = __self.lower_bound(__key); + auto __last = __self.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return __last; + } + return __it; + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __equal_range_impl(_Self&& __self, const _Kp& __key) { + auto __it = ranges::lower_bound(__self.__keys_, __key, __self.__compare_); + auto __last = __self.__keys_.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return std::make_pair(__it, __it); + } + return std::make_pair(__it, std::next(__it)); + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_exact_pos(const_iterator __it, _KeyArg&& __key) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { + if constexpr (!__container_traits<_KeyContainer>::__emplacement_has_strong_exception_safety_guarantee) { + clear() /* noexcept */; + } + }); + auto __key_it = __keys_.emplace(__it, std::forward<_KeyArg>(__key)); + __on_failure.__complete(); + return __key_it; + } + + template + _LIBCPP_HIDE_FROM_ABI pair __try_emplace(_Kp&& __key) { + auto __it = lower_bound(__key); + if (__it == end() || __compare_(__key, *__it)) { + return pair(__emplace_exact_pos(__it, std::forward<_Kp>(__key)), true); + } else { + return pair(std::move(__it), false); + } + } + + template + _LIBCPP_HIDE_FROM_ABI bool __is_hint_correct(const_iterator __hint, _Kp&& __key) { + if (__hint != cbegin() && !__compare_(*(__hint - 1), __key)) { + return false; + } + if (__hint != cend() && __compare_(*__hint, __key)) { + return false; + } + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint(const_iterator __hint, _Kp&& __key) { + if (__is_hint_correct(__hint, __key)) { + if (__hint == cend() || __compare_(__key, *__hint)) { + return __emplace_exact_pos(__hint, std::forward<_Kp>(__key)); + } else { + // key equals + return __hint; + } + } else { + return __try_emplace(std::forward<_Kp>(__key)).first; + } + } + + _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __size) { + if constexpr (requires { __keys_.reserve(__size); }) { + __keys_.reserve(__size); + } + } + + template + friend typename flat_set<_Key2, _Compare2, _KeyContainer2>::size_type + erase_if(flat_set<_Key2, _Compare2, _KeyContainer2>&, _Predicate); + + _KeyContainer __keys_; + _LIBCPP_NO_UNIQUE_ADDRESS key_compare __compare_; + + struct __key_equiv { + _LIBCPP_HIDE_FROM_ABI __key_equiv(key_compare __c) : __comp_(__c) {} + _LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const { + return !__comp_(__x, __y) && !__comp_(__y, __x); + } + key_compare __comp_; + }; +}; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(_KeyContainer, _Compare = _Compare()) -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(_KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(_KeyContainer, _Compare, _Allocator) -> flat_set; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare = _Compare()) + -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(sorted_unique_t, _KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare, _Allocator) + -> flat_set; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(_InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >, + class _Allocator = allocator, + class = __enable_if_t::value && __is_allocator<_Allocator>::value>> +flat_set(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> flat_set< + ranges::range_value_t<_Range>, + _Compare, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template ::value>> +flat_set(from_range_t, _Range&&, _Allocator) -> flat_set< + ranges::range_value_t<_Range>, + less>, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template +struct uses_allocator, _Allocator> + : bool_constant> {}; + + template + _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type + erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; + } + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FLAT_set_FLAT_SET_H diff --git a/libcxx/include/flat_set b/libcxx/include/flat_set new file mode 100644 index 00000000000000..d03645fafafdba --- /dev/null +++ b/libcxx/include/flat_set @@ -0,0 +1,59 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_FLAT_SET +#define _LIBCPP_FLAT_SET + +/* + Header synopsis + +#include // see [compare.syn] +#include // see [initializer.list.syn] + +namespace std { + // [flat.set], class template flat_set + template, class KeyContainer = vector> + class flat_set; + + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + + template + struct uses_allocator, Allocator>; + + // [flat.set.erasure], erasure for flat_set + template + typename flat_set::size_type + erase_if(flat_set& c, Predicate pred); +} +*/ + +#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +# include <__cxx03/__config> +#else +# include <__config> + +# if _LIBCPP_STD_VER >= 23 +# include <__flat_map/sorted_unique.h> +# include <__flat_set/flat_set.h> +# endif + +// for feature-test macros +# include + +// standard required includes +# include +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif +#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) + +#endif // _LIBCPP_FLAT_SET diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4bae02137b37b2..abc351d5923963 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1263,6 +1263,17 @@ module std [system] { export * } + module flat_set { + module flat_set { + header "__flat_set/flat_set.h" + export std.vector.vector + export std.vector.fwd + } + + header "flat_set" + export * + } + module format { module buffer { header "__format/buffer.h" diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp new file mode 100644 index 00000000000000..204df1d681af1b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m; + ASSERT_SAME_TYPE(decltype(m.empty()), bool); + ASSERT_NOEXCEPT(m.empty()); + assert(m.empty()); + assert(std::as_const(m).empty()); + m = {1}; + assert(!m.empty()); + m.clear(); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp new file mode 100644 index 00000000000000..161fe533eabacb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include + +void f() { + std::flat_set c; + c.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp new file mode 100644 index 00000000000000..cd7f424e00ece2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type max_size() const noexcept; + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_allocator.h" +#include "test_macros.h" + +int main(int, char**) { + { + using A1 = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= 10); + LIBCPP_ASSERT(c.max_size() == 10); + } + { + using A = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + LIBCPP_ASSERT(c.max_size() == max_dist); + } + { + typedef std::flat_set C; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + assert(c.max_size() <= alloc_max_size(std::allocator())); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp new file mode 100644 index 00000000000000..7c156e95ecb1c8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type size() const noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using M = std::flat_set, KeyContainer>; + using S = typename M::size_type; + { + const M m = {1, 1, 4, 5, 5}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 3); + } + { + const M m = {1}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 1); + } + { + const M m; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 0); + } + { + M m; + S s = 1000000; + for (auto i = 0u; i < s; ++i) { + m.emplace(i); + } + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == s); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp new file mode 100644 index 00000000000000..acc0817d7cac4d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// explicit flat_set(const Allocator& a); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // explicit + using M = std::flat_set, std::vector>>; + + static_assert(std::is_constructible_v>); + static_assert(!std::is_convertible_v, M>); + } + { + using A = test_allocator; + using M = std::flat_set, std::vector>>; + M m(A(0, 5)); + assert(m.empty()); + assert(m.begin() == m.end()); + auto v = std::move(m).extract(); + assert(v.get_allocator().get_id() == 5); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp new file mode 100644 index 00000000000000..7f75f1e1611e3b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(initializer_list il); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m = {8, 10}; + assert(m.size() == 2); + m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + int expected[] = {1, 2, 3, 4, 5, 6}; + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + } + { + M m = {10, 8}; + assert(m.size() == 2); + m = {3}; + int expected[] = {3}; + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp new file mode 100644 index 00000000000000..b3bee18f5a936b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(const key_compare& comp); +// template +// flat_set(const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + auto m = std::flat_set(C(3)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(3)); + } + { + // The one-argument ctor is explicit. + using C = test_less; + static_assert(std::is_constructible_v, C>); + static_assert(!std::is_convertible_v>); + + static_assert(std::is_constructible_v, std::less>); + static_assert(!std::is_convertible_v, std::flat_set>); + } + { + using C = test_less; + using A1 = test_allocator; + auto m = std::flat_set>(C(4), A1(5)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + { + // explicit(false) + using C = test_less; + using A1 = test_allocator; + std::flat_set> m = {C(4), A1(5)}; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp new file mode 100644 index 00000000000000..3d1e6240c952e8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -0,0 +1,158 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(container_type key_cont, const key_compare& comp = key_compare()); +// template +// flat_set(const container_type& key_cont, const Allocator& a); +// template +// flat_set(const container_type& key_cont, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(container_type) + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + + // explicit + static_assert(std::is_constructible_v&>); + static_assert(!ImplicitlyConstructible&>); + } + { + // flat_set(container_type) + // move-only + MoveOnly expected[] = {3, 2, 1}; + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks; + ks.push_back(1); + ks.push_back(3); + ks.push_back(2); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(container_type) + // container's allocator is used + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(5)); + } + { + // flat_set(container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + + // explicit + static_assert(std::is_constructible_v&, const C&>); + static_assert(!ImplicitlyConstructible&, const C&>); + } + { + // flat_set(container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(ks, A(4)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , const Allocator&) + // explicit(false) + using A = test_allocator; + using M = std::flat_set, std::deque>; + static_assert(ImplicitlyConstructible&, const A&>); + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + M m = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4), A(5)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + auto m_copy = m; + auto keys = std::move(m_copy).extract(); + assert(keys.get_allocator() == A(5)); + + // explicit(false) + static_assert(ImplicitlyConstructible&, const A&>); + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + keys = std::move(m2).extract(); + assert(keys.get_allocator() == A(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp new file mode 100644 index 00000000000000..f1dbc955e1b0de --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(-2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp new file mode 100644 index 00000000000000..59fb9d0a38366f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M(mo, test_allocator(3)); + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(3)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp new file mode 100644 index 00000000000000..169b469f3bca68 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& s); + +// Validate whether the container can be copy-assigned (move-assigned, swapped) +// with an ADL-hijacking operator& + +#include +#include + +#include "test_macros.h" +#include "operator_hijacker.h" + +void test() { + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp new file mode 100644 index 00000000000000..cdd5045f4bb9f7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // test_allocator is not propagated + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M({{3, 4, 5}}, C(3), test_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + // other_allocator is propagated + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = M({3, 4, 5}, C(3), other_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + { + // comparator is copied and invariant is preserved + using M = std::flat_set>; + M mo = M({1, 2}, std::less()); + M m = M({1, 2}, std::greater()); + assert(m.key_comp()(2, 1) == true); + assert(m != mo); + m = mo; + assert(m.key_comp()(2, 1) == false); + assert(m == mo); + } + { + // self-assignment + using M = std::flat_set; + M m = {{1, 2}}; + m = static_cast(m); + assert((m == M{{1, 2}})); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp new file mode 100644 index 00000000000000..5db8c4ca722466 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Test CTAD on cases where deduction should fail. + +#include +#include +#include +#include +#include + +struct NotAnAllocator { + friend bool operator<(NotAnAllocator, NotAnAllocator) { return false; } +}; + +template +concept CanDeductFlatSet = requires { std::flat_set{std::declval()...}; }; + +static_assert(CanDeductFlatSet, std::vector>); + +// cannot deduce Key and T from nothing +static_assert(!CanDeductFlatSet<>); + +// cannot deduce Key and T from just (KeyContainer), even if it's a container of pairs +static_assert(!CanDeductFlatSet>>); + +// cannot deduce Key and T from just (KeyContainer, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>>); + +// cannot deduce Key and T from just (Compare) +static_assert(!CanDeductFlatSet>); + +// cannot deduce Key and T from just (Compare, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>); + +// cannot deduce Key and T from just (Allocator) +static_assert(!CanDeductFlatSet>); + +// cannot convert from some arbitrary unrelated type +static_assert(!CanDeductFlatSet); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp new file mode 100644 index 00000000000000..612e64a7c42f23 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -0,0 +1,341 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "deduction_guides_sfinae_checks.h" +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_copy() { + { + std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set s(source); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s{source}; // braces instead of parens + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s(source, std::allocator()); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } +} + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(ks, vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(ks, vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_iter_iter() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m(std::begin(arr), std::end(arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) + static_assert(std::is_same_v>); + assert(s.size() == 3); + } +} + +void test_iter_iter_compare() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m(std::begin(arr), std::end(arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } +} + +void test_initializer_list() { + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } + { + using M = std::flat_set; + M m; + std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + assert(s[m] == m); + } +} + +void test_initializer_list_compare() { + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } +} + +void test_from_range() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(std::from_range, r); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +void test_from_range_compare() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(std::from_range, r, std::greater()); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +int main(int, char**) { + // Each test function also tests the sorted_unique-prefixed and allocator-suffixed overloads. + test_copy(); + test_containers(); + test_containers_compare(); + test_iter_iter(); + test_iter_iter_compare(); + test_initializer_list(); + test_initializer_list_compare(); + test_from_range(); + test_from_range_compare(); + + AssociativeContainerDeductionGuidesSfinaeAway>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp new file mode 100644 index 00000000000000..df8d6d885ee524 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + const int expected[] = {1, 2, 3, INT_MAX}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + const int expected[] = {INT_MAX, 3, 2, 1}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +int main(int, char**) { + test_containers(); + test_containers_compare(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp new file mode 100644 index 00000000000000..64b0bfcb383a72 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + std::flat_set m; + assert(m.empty()); + } + { + // explicit(false) + std::flat_set m = {}; + assert(m.empty()); + } + { + std::flat_set>> m; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp().default_constructed_); + } + { + using A1 = explicit_allocator; + using A2 = explicit_allocator; + { + std::flat_set> m; + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + { + A1 a1; + std::flat_set> m(a1); + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp new file mode 100644 index 00000000000000..b4a3b6de205a31 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set() +// noexcept( +// is_nothrow_default_constructible_v && +// is_nothrow_default_constructible_v); + +// This tests a conforming extension + +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +int main(int, char**) { +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp new file mode 100644 index 00000000000000..c0d315c0ce74b4 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// ~flat_set(); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingDtorComp { + bool operator()(const auto&, const auto&) const; + ~ThrowingDtorComp() noexcept(false) {} +}; + +int main(int, char**) { + { + using C = std::flat_set; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::vector>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::deque>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(!std::is_nothrow_destructible_v); + C c; + } +#endif // _LIBCPP_VERSION + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp new file mode 100644 index 00000000000000..cd2319e91f760d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -0,0 +1,151 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(initializer_list il, const key_compare& comp = key_compare()); +// template +// flat_set(initializer_list il, const Alloc& a); +// template +// flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +#include "../../../test_compare.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + } + + int expected[] = {1, 2, 3, 5}; + { + // flat_set(initializer_list); + using M = std::flat_set; + std::initializer_list il = {5, 2, 2, 3, 1, 3}; + M m(il); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + // explicit(false) + using M = std::flat_set; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + using M = std::flat_set, std::deque>>; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + { + using A = explicit_allocator; + { + // flat_set(initializer_list); + // different comparator + using M = std::flat_set>; + M m = {1, 2, 3}; + assert(m.size() == 1); + LIBCPP_ASSERT(*m.begin() == 1); + assert(m.key_comp().default_constructed_); + } + { + // flat_set(initializer_list, const Allocator&); + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + } + { + // flat_set(initializer_list, const key_compare&); + using C = test_less; + using M = std::flat_set; + auto m = M({5, 2, 2, 3, 1, 3}, C(10)); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + assert(m.key_comp() == C(10)); + + // explicit(false) + M m2 = {{5, 2, 2, 1, 3, 3}, C(10)}; + assert(m2 == m); + assert(m2.key_comp() == C(10)); + } + { + // flat_set(initializer_list, const key_compare&); + // Sorting uses the comparator that was passed in + using M = std::flat_set, std::deque>>; + auto m = M({5, 2, 2, 1, 3, 1}, std::greater()); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + assert(m.key_comp()(2, 1) == true); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using A = explicit_allocator; + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, {}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp new file mode 100644 index 00000000000000..65eebc21a66c4c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(InputIterator first, InputIterator last, const Allocator& a); +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(InputIterator , InputIterator) + // cpp17_input_iterator + using M = std::flat_set; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)}; + assert(m2 == m); + } + { + // flat_set(InputIterator , InputIterator) + // greater + using M = std::flat_set, std::deque>>; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(InputIterator , InputIterator) + // Test when the operands are of array type (also contiguous iterator type) + using M = std::flat_set, std::vector>>; + auto m = M(ar, ar); + assert(m.empty()); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&) + using C = test_less; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {ar, ar + 9, C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + auto m = M(ar, ar + 9, A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + M m = {ar, ar + 9, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {ar, ar + 9, {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp new file mode 100644 index 00000000000000..69b340ad09fe15 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A(7)); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A(7)); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().get_id() == test_alloc_base::moved_value); + } + { + using C = test_less; + using A = min_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A()); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A()); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A()); + } + { + // A moved-from flat_set maintains its class invariant in the presence of moved-from comparators. + using M = std::flat_set>; + M mo = M({1, 2, 3}, std::less()); + M m = std::move(mo); + assert(m.size() == 3); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.key_comp()(1, 2) == true); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + LIBCPP_ASSERT(m.key_comp()(1, 2) == true); + LIBCPP_ASSERT(mo.empty()); + mo.insert({1, 2, 3}); // insert has no preconditions + assert(m == mo); + } + { + // moved-from object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m1.size() == 0); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp new file mode 100644 index 00000000000000..fc7f68d8c967ad --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + int expected[] = {1, 2, 3}; + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + auto mo = M(expected, expected + 3, C(5), A(7)); + auto m = M(std::move(mo), A(3)); + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(3)); + assert(std::ranges::equal(keys, expected )); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A(7)); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2(std::move(m1), std::allocator{}); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp new file mode 100644 index 00000000000000..b16dc38dd40285 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{4, 5})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + m = std::move(mo); + assert((m == M{5, 4, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A()); + assert(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp new file mode 100644 index 00000000000000..50817f4be8a812 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); +// Preserves the class invariant for the moved-from flat_set. + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +int main(int, char**) { + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp new file mode 100644 index 00000000000000..86f3568f0d67a6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&& c) +// noexcept( +// is_nothrow_move_assignable::value && +// is_nothrow_move_assignable::value && +// is_nothrow_copy_assignable::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_macros.h" + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp new file mode 100644 index 00000000000000..17e4e40387606c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// flat_set(flat_set&& s); +// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +int main(int, char**) { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp new file mode 100644 index 00000000000000..49d1151fd8a993 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&) +// noexcept(is_nothrow_move_constructible::value && +// is_nothrow_move_constructible::value && +// is_nothrow_copy_constructible::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp new file mode 100644 index 00000000000000..785718d2eed333 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -0,0 +1,322 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +// Test various constructors with pmr + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // flat_set(const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::polymorphic_allocator pa = &mr; + auto m1 = M(pa); + assert(m1.empty()); + assert(std::move(m1).extract().get_allocator() == pa); + auto m2 = M(&mr); + assert(m2.empty()); + assert(std::move(m2).extract().get_allocator() == pa); + } + { + // flat_set(const key_compare& comp, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::greater()); + assert(vm[0] == M{}); + assert(vm[0].key_comp()(2, 1) == true); + assert(vm[0].value_comp()(2, 1) == true); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + // const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + assert(ks.get_allocator().resource() != &mr); + vm.emplace_back(ks); + assert(ks.size() == 9); // ks' value is unchanged, since it was an lvalue above + assert((vm[0] == M{1, 2, 3})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const flat_set&, const allocator_type&); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, C(5), &mr1); + M m = {mo, &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + auto keys = std::move(m).extract(); + assert((keys == std::pmr::vector{1, 2, 3})); + assert(keys.get_allocator().resource() == &mr2); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + auto keys2 = std::move(mo).extract(); + assert((keys2 == std::pmr::vector{1, 2, 3})); + assert(keys2.get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set&, const allocator_type&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::vector vs; + M m = {1, 2, 3}; + vs.push_back(m); + assert(vs[0] == m); + } + { + // flat_set& operator=(const flat_set& m); + // pmr allocator is not propagated + using M = std::flat_set, std::pmr::deque>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, &mr1); + M m = M({4, 5}, &mr2); + m = mo; + assert((m == M{1, 2, 3})); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // mo is unchanged + assert((mo == M{1, 2, 3})); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set& m); + using C = test_less; + std::pmr::monotonic_buffer_resource mr; + using M = std::flat_set>; + auto mo = M({1, 2, 3}, C(5), &mr); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert((m == M{1, 2, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator().resource() == std::pmr::get_default_resource()); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert((mo == M{1, 2, 3})); + auto kso = std::move(mo).extract(); + assert(kso.get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il, C(5)); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + assert(vm[0].key_comp() == C(5)); + } + { + // flat_set(InputIterator first, InputIterator last, const Allocator& a); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // cpp17 iterator + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(ar, ar); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(flat_set&&, const allocator_type&); + int expected[] = {1, 2, 3}; + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 3, 1, 2}, C(5), &mr1); + M m = {std::move(mo), &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + assert(std::equal(m.begin(), m.end(), expected, expected + 3)); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(flat_set&&, const allocator_type&); + using M = std::flat_set, std::pmr::deque>; + std::pmr::vector vs; + M m = {1, 3, 1, 2}; + vs.push_back(std::move(m)); + assert((std::move(vs[0]).extract() == std::pmr::deque{1, 2, 3})); + } + { + // flat_set& operator=(flat_set&&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = + M({"short", "very long string that definitely won't fit in the SSO buffer and therefore becomes empty on move"}, + &mr1); + M m = M({"don't care"}, &mr2); + m = std::move(mo); + assert(m.size() == 2); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.begin()->get_allocator().resource() == &mr2); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + mo.insert("foo"); + assert(mo.begin()->get_allocator().resource() == &mr1); + } + { + // flat_set(from_range_t, R&&, const Alloc&); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // input_range + using M = std::flat_set, std::pmr::vector>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(ar, ar)); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 2, 4, 10}; + vm.emplace_back(std::sorted_unique, ks); + assert(!ks.empty()); // it was an lvalue above + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, const container_type& key_cont,const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks({1, 2, 4, 10}, &mr); + vm.emplace_back(std::sorted_unique, ks); + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp new file mode 100644 index 00000000000000..bb9f99c228bfec --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -0,0 +1,173 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// flat_set(from_range_t, R&&) +// template R> +// flat_set(from_range_t, R&&, const key_compare&) +// template R, class Alloc> +// flat_set(from_range_t, R&&, const Alloc&); +// template R, class Alloc> +// flat_set(from_range_t, R&&, const key_compare&, const Alloc&); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +// test constraint container-compatible-range + +template +using RangeOf = std::ranges::subrange; +using Set = std::flat_set; + +static_assert(std::is_constructible_v>); +static_assert(std::is_constructible_v>); +static_assert(!std::is_constructible_v>>); + +static_assert(std::is_constructible_v, std::less>); +static_assert(std::is_constructible_v, std::less>); +static_assert(!std::is_constructible_v>, std::less>); + +static_assert(std::is_constructible_v, std::allocator>); +static_assert(std::is_constructible_v, std::allocator>); +static_assert(!std::is_constructible_v>, std::allocator>); + +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert( + !std:: + is_constructible_v>, std::less, std::allocator>); + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(from_range_t, R&&) + // input_range && !common + using M = std::flat_set; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))}; + assert(m2 == m); + } + { + // flat_set(from_range_t, R&&) + // greater + using M = std::flat_set, std::deque>>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(from_range_t, R&&) + // contiguous range + using M = std::flat_set; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9)); + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(from_range_t, R&&, const key_compare&) + using C = test_less; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {std::from_range, R(ar, ar + 9), C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp new file mode 100644 index 00000000000000..2d442d49667bd0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(sorted_unique_t, container_type key_cont, const key_compare& comp = key_compare()); +// +// template +// flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); +// template +// flat_set(sorted_unique_t, const container_type& key_cont, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, container_type) + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + auto ks2 = ks; + + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + + // explicit(false) + M m2 = {std::sorted_unique, std::move(ks2)}; + assert(m == m2); + } + { + // flat_set(sorted_unique_t, container_type) + // non-default container, comparator and allocator type + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks = {10, 4, 2, 1}; + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + } + { + // flat_set(sorted_unique_t, container_type) + // allocator copied into the containers + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + assert(std::move(m).extract().get_allocator() == A(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + + auto m = M(std::sorted_unique, ks, C(4)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, C(4)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 2, 4, 10}; + auto m = M(std::sorted_unique, ks, C(4), A(5)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + assert(M(m).extract().get_allocator() == A(5)); + + // explicit(false) + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + assert(std::move(m2).extract().get_allocator() == A(5)); + } + { + // flat_set(sorted_unique_t, container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, ks, A(6)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 4, 10})); + assert(M(m).extract().get_allocator() == A(6)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, A(6)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp new file mode 100644 index 00000000000000..01956a78c7f48d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t s, initializer_list il, +// const key_compare& comp = key_compare()) +// template +// flat_set(sorted_unique_t, initializer_list il, const Alloc& a); +// template +// flat_set(sorted_unique_t, initializer_list il, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +std::initializer_list il = {1, 2, 4, 5}; + +const auto il1 = il; +const auto il2 = il; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + } + + { + // flat_set(sorted_unique_t, initializer_list); + using M = std::flat_set; + auto m = M(std::sorted_unique, il1); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, il1}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + using M = std::flat_set>; + auto m = M(std::sorted_unique, il1, std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, il1, std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + std::initializer_list il4{5, 4, 2, 1}; + auto m = M(std::sorted_unique, il4, std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, initializer_list, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + auto m = M(std::sorted_unique, il2, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, il2, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(std::sorted_unique, il2, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {std::sorted_unique, il2, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp new file mode 100644 index 00000000000000..b5229a84dd5133 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // cpp17_input_iterator + using M = std::flat_set; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // cpp_17_input_iterator + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + int ar[] = {5, 4, 2, 1}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[1] = {42}; + auto m = M(std::sorted_unique, ar, ar, C(5)); + assert(m.empty()); + assert(m.key_comp() == C(5)); + } + { + // flat_set(sorted_unique_t, InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, ar, ar + 4, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + int ar[] = {1, 2, 4, 5}; + M m = {std::sorted_unique, ar, ar + 4, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp new file mode 100644 index 00000000000000..134db83aef3cad --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "min_allocator.h" + +// Verify that `flat_set` (like `set`) does NOT support std::erase. +// +template +concept HasStdErase = requires(S& s, typename S::value_type x) { std::erase(s, x); }; +static_assert(HasStdErase>); +static_assert(!HasStdErase>); + +template +M make(std::initializer_list vals) { + M ret; + for (int v : vals) + ret.emplace(v); + return ret; +} + +template +void test0( + std::initializer_list vals, Pred p, std::initializer_list expected, std::size_t expected_erased_count) { + M s = make(vals); + ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p))); + assert(expected_erased_count == std::erase_if(s, p)); + assert(s == make(expected)); +} + +template +void test() { + // Test all the plausible signatures for this predicate. + auto is1 = [](typename S::const_reference v) { return v == 1; }; + auto is2 = [](typename S::value_type v) { return v == 2; }; + auto is3 = [](const typename S::value_type& v) { return v == 3; }; + auto is4 = [](auto v) { return v == 4; }; + auto True = [](const auto&) { return true; }; + auto False = [](auto&&) { return false; }; + + test0({}, is1, {}, 0); + + test0({1}, is1, {}, 1); + test0({1}, is2, {1}, 0); + + test0({1, 2}, is1, {2}, 1); + test0({1, 2}, is2, {1}, 1); + test0({1, 2}, is3, {1, 2}, 0); + + test0({1, 2, 3}, is1, {2, 3}, 1); + test0({1, 2, 3}, is2, {1, 3}, 1); + test0({1, 2, 3}, is3, {1, 2}, 1); + test0({1, 2, 3}, is4, {1, 2, 3}, 0); + + test0({1, 2, 3}, True, {}, 3); + test0({1, 2, 3}, False, {1, 2, 3}, 0); +} + +int main(int, char**) { + test>(); + test, std::vector>>>(); + test, std::vector>>>(); + test, std::deque>>>(); + test, std::deque>>>(); + test>(); + test>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp new file mode 100644 index 00000000000000..6bbe1ad4f01670 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -0,0 +1,128 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); +// If any member function in [flat.set.defn] exits via an exception, the invariant is restored. +// (This is not a member function, but let's respect the invariant anyway.) + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct Counter { + int c1, c2, throws; + void tick() { + c1 -= 1; + if (c1 == 0) { + c1 = c2; + throws += 1; + throw 42; + } + } +}; +Counter g_counter = {0, 0, 0}; + +struct ThrowingAssignment { + ThrowingAssignment(int i) : i_(i) {} + ThrowingAssignment(const ThrowingAssignment&) = default; + ThrowingAssignment& operator=(const ThrowingAssignment& rhs) { + g_counter.tick(); + i_ = rhs.i_; + g_counter.tick(); + return *this; + } + operator int() const { return i_; } + int i_; +}; + +struct ThrowingComparator { + bool operator()(const ThrowingAssignment& a, const ThrowingAssignment& b) const { + g_counter.tick(); + return a.i_ < b.i_; + } +}; + +struct ErasurePredicate { + bool operator()(const auto& x) const { return (3 <= x && x <= 5); } +}; + +int main(int, char**) { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + { + using M = std::flat_set; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + M m = M({1, 2, 3, 4, 5, 6, 7, 8}); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + + { + using M = std::flat_set>; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + std::deque container = {5, 6, 7, 8}; + container.insert(container.begin(), {1, 2, 3, 4}); + M m = M(std::move(container)); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp new file mode 100644 index 00000000000000..c07297a141ad10 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator begin() noexcept; +// const_iterator begin() const noexcept +// iterator end() noexcept; +// const_iterator end() const noexcept; +// +// const_iterator cbegin() const noexcept; +// const_iterator cend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.begin()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cbegin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.begin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(m.end()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cend()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.end()), typename M::const_iterator); + static_assert(noexcept(m.begin())); + static_assert(noexcept(cm.begin())); + static_assert(noexcept(m.cbegin())); + static_assert(noexcept(m.end())); + static_assert(noexcept(cm.end())); + static_assert(noexcept(m.cend())); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(std::distance(cm.begin(), cm.end()) == 4); + assert(std::distance(m.cbegin(), m.cend()) == 4); + typename M::iterator i; // default-construct + i = m.begin(); // move-assignment + typename M::const_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 1; j <= 4; ++j, ++i) { // pre-increment + assert(*i == j); // operator* + } + assert(i == m.end()); + for (int j = 4; j >= 1; --j) { + --i; // pre-decrement + assert((*i) == j); + } + assert(i == m.begin()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // N3644 testing + using C = std::flat_set; + C::iterator ii1{}, ii2{}; + C::iterator ii4 = ii1; + C::const_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp new file mode 100644 index 00000000000000..29441dcc57d40e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set iterators should be C++20 random access iterators + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using KI = typename KeyContainer::iterator; + using I = M::iterator; + using CI = M::const_iterator; + using RI = M::reverse_iterator; + using CRI = M::const_reverse_iterator; + + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + + M m = {1, 2, 3, 4}; + + I i1 = m.begin(); + I i2 = m.begin() + 1; + + assert(i1 == i1); + assert(!(i1 != i1)); + assert(i1 != i2); + assert(!(i1 == i2)); + assert(i1 < i2); + assert(!(i1 < i1)); + assert(i1 <= i1); + assert(i1 <= i2); + assert(!(i2 <= i1)); + assert(i2 > i1); + assert(!(i2 > i2)); + assert(i2 >= i1); + assert(i2 >= i2); + assert(!(i1 >= i2)); + + CI ci1 = m.cbegin(); + CI ci2 = m.cbegin() + 1; + assert(ci1 == ci1); + assert(!(ci1 != ci1)); + assert(ci1 != ci2); + assert(!(ci1 == ci2)); + assert(ci1 < ci2); + assert(!(ci1 < ci1)); + assert(ci1 <= ci1); + assert(ci1 <= ci2); + assert(!(ci2 <= ci1)); + assert(ci2 > ci1); + assert(!(ci2 > ci2)); + assert(ci2 >= ci1); + assert(ci2 >= ci2); + assert(!(ci1 >= ci2)); + + RI ri1 = m.rbegin(); + RI ri2 = m.rbegin() + 1; + assert(ri1 == ri1); + assert(!(ri1 != ri1)); + assert(ri1 != ri2); + assert(!(ri1 == ri2)); + assert(ri1 < ri2); + assert(!(ri1 < ri1)); + assert(ri1 <= ri1); + assert(ri1 <= ri2); + assert(!(ri2 <= ri1)); + assert(ri2 > ri1); + assert(!(ri2 > ri2)); + assert(ri2 >= ri1); + assert(ri2 >= ri2); + assert(!(ri1 >= ri2)); + + CRI cri1 = m.crbegin(); + CRI cri2 = m.crbegin() + 1; + assert(cri1 == cri1); + assert(!(cri1 != cri1)); + assert(cri1 != cri2); + assert(!(cri1 == cri2)); + assert(cri1 < cri2); + assert(!(cri1 < cri1)); + assert(cri1 <= cri1); + assert(cri1 <= cri2); + assert(!(cri2 <= cri1)); + assert(cri2 > cri1); + assert(!(cri2 > cri2)); + assert(cri2 >= cri1); + assert(cri2 >= cri2); + assert(!(cri1 >= cri2)); + + if constexpr (std::three_way_comparable) { + static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::same_as I()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as RI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + + assert(i1 <=> i1 == std::strong_ordering::equivalent); + assert(i1 <=> i2 == std::strong_ordering::less); + assert(i2 <=> i1 == std::strong_ordering::greater); + + assert(ci1 <=> ci1 == std::strong_ordering::equivalent); + assert(ci1 <=> ci2 == std::strong_ordering::less); + assert(ci2 <=> ci1 == std::strong_ordering::greater); + + assert(ri1 <=> ri1 == std::strong_ordering::equivalent); + assert(ri1 <=> ri2 == std::strong_ordering::less); + assert(ri2 <=> ri1 == std::strong_ordering::greater); + + assert(cri1 <=> cri1 == std::strong_ordering::equivalent); + assert(cri1 <=> cri2 == std::strong_ordering::less); + assert(cri2 <=> cri1 == std::strong_ordering::greater); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp new file mode 100644 index 00000000000000..35b45b6e797233 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator, const_iterator, reverse_iterator, const_reverse_iterator + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + using I = C::iterator; + using CI = C::const_iterator; + using RI = C::reverse_iterator; + using CRI = C::const_reverse_iterator; + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp new file mode 100644 index 00000000000000..4ec64e706b7021 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include +#include +#include +#include +#include +#include "MinSequenceContainer.h" +#include "min_allocator.h" + +template +void test() { + { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + + static_assert(std::same_as, typename C::iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(std::ranges::viewable_range); + + static_assert(std::same_as, typename C::const_iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(!std::ranges::viewable_range); + } +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp new file mode 100644 index 00000000000000..a16383cdcf5383 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// reverse_iterator rbegin() noexcept; +// const_reverse_iterator rbegin() const noexcept; +// reverse_iterator rend() noexcept; +// const_reverse_iterator rend() const noexcept; +// +// const_reverse_iterator crbegin() const noexcept; +// const_reverse_iterator crend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include + +#include "test_macros.h" +#include + +int main(int, char**) { + { + using M = std::flat_set, std::deque>; + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.rbegin()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.rend()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crend()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rend()), M::const_reverse_iterator); + static_assert(noexcept(m.rbegin())); + static_assert(noexcept(cm.rbegin())); + static_assert(noexcept(m.crbegin())); + static_assert(noexcept(m.rend())); + static_assert(noexcept(cm.rend())); + static_assert(noexcept(m.crend())); + assert(m.size() == 4); + assert(std::distance(m.rbegin(), m.rend()) == 4); + assert(std::distance(cm.rbegin(), cm.rend()) == 4); + assert(std::distance(m.crbegin(), m.crend()) == 4); + assert(std::distance(cm.crbegin(), cm.crend()) == 4); + M::reverse_iterator i; // default-construct + ASSERT_SAME_TYPE(decltype(*i), const int&); + i = m.rbegin(); // move-assignment + M::const_reverse_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 4; j >= 1; --j, ++i) { // pre-increment + assert(*i == j); + } + assert(i == m.rend()); + for (int j = 1; j <= 4; ++j) { + --i; // pre-decrement + assert(*i == j); + } + assert(i == m.rbegin()); + } + { + // N3644 testing + using C = std::flat_set; + C::reverse_iterator ii1{}, ii2{}; + C::reverse_iterator ii4 = ii1; + C::const_reverse_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp new file mode 100644 index 00000000000000..221a13fa057577 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// void clear() noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// test noexcept + +template +concept NoExceptClear = requires(T t) { + { t.clear() } noexcept; +}; + +static_assert(NoExceptClear>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptClear, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4, 5}; + assert(m.size() == 5); + ASSERT_NOEXCEPT(m.clear()); + ASSERT_SAME_TYPE(decltype(m.clear()), void); + m.clear(); + assert(m.size() == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp new file mode 100644 index 00000000000000..95f7a3c5f5d34a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -0,0 +1,141 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// pair emplace(Args&&... args); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the begin + M m = {3, 5, 6, 7}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted in the middle + M m = {0, 1, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the end + M m = {0, 1}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } + { + // key already exists and original at the begin + M m = {2, 3, 5, 6}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original in the middle + M m = {0, 2, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 1); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original at the end + M m = {0, 1, 2}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace()), R); + R r = m.emplace(2, 0.0); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace(1, 3.5); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace(1, 3.5); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp new file mode 100644 index 00000000000000..de855d5e5c3009 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// iterator emplace_hint(const_iterator position, Args&&... args); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace_hint(m.end(), typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + } + { + // hints correct at the begin + M m = {3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints correct at the end + M m = {0, 1}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct but key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the begin + M m = {1, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrectly in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 1; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the end + M m = {0, 3}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrect and key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace_hint(m.cbegin())), R); + R r = m.emplace_hint(m.end(), 2, 0.0); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp new file mode 100644 index 00000000000000..386af04d26e9a2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(iterator position); +// iterator erase(const_iterator position); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(std::next(m.cbegin(), 3)); + assert(m.size() == 7); + assert(i1 == std::next(m.begin(), 3)); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 5); + assert(*std::next(m.begin(), 4) == 6); + assert(*std::next(m.begin(), 5) == 7); + assert(*std::next(m.begin(), 6) == 8); + + std::same_as decltype(auto) i2 = m.erase(std::next(m.begin(), 0)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 5)); + assert(m.size() == 5); + assert(i3 == m.end()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + + std::same_as decltype(auto) i4 = m.erase(std::next(m.begin(), 1)); + assert(m.size() == 4); + assert(i4 == std::next(m.begin())); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 6); + assert(*std::next(m.begin(), 3) == 7); + + std::same_as decltype(auto) i5 = m.erase(std::next(m.cbegin(), 2)); + assert(m.size() == 3); + assert(i5 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 7); + + std::same_as decltype(auto) i6 = m.erase(std::next(m.begin(), 2)); + assert(m.size() == 2); + assert(i6 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + + std::same_as decltype(auto) i7 = m.erase(std::next(m.cbegin(), 0)); + assert(m.size() == 1); + assert(i7 == std::next(m.begin(), 0)); + assert(*m.begin() == 5); + + std::same_as decltype(auto) i8 = m.erase(m.begin()); + assert(m.size() == 0); + assert(i8 == m.begin()); + assert(i8 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp new file mode 100644 index 00000000000000..7416977844e5df --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(const_iterator first, const_iterator last); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(m.cbegin(), m.cbegin()); + assert(m.size() == 8); + assert(i1 == m.begin()); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 4); + assert(*std::next(m.begin(), 4) == 5); + assert(*std::next(m.begin(), 5) == 6); + assert(*std::next(m.begin(), 6) == 7); + assert(*std::next(m.begin(), 7) == 8); + + std::same_as decltype(auto) i2 = m.erase(m.cbegin(), std::next(m.cbegin(), 2)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 2), std::next(m.cbegin(), 6)); + assert(m.size() == 2); + assert(i3 == std::next(m.begin(), 2)); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + + std::same_as decltype(auto) i4 = m.erase(m.cbegin(), m.cend()); + assert(m.size() == 0); + assert(i4 == m.begin()); + assert(i4 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp new file mode 100644 index 00000000000000..25d4f4af19608b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(const key_type& k); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template > +void test() { + using M = std::flat_set; + + auto make = [](std::initializer_list il) { + M m; + for (int i : il) { + m.emplace(i); + } + return m; + }; + M m = make({1, 2, 3, 4, 5, 6, 7, 8}); + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(9); + assert(n == 0); + assert(m == make({1, 2, 3, 4, 5, 6, 7, 8})); + n = m.erase(4); + assert(n == 1); + assert(m == make({1, 2, 3, 5, 6, 7, 8})); + n = m.erase(1); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7, 8})); + n = m.erase(8); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7})); + n = m.erase(3); + assert(n == 1); + assert(m == make({2, 5, 6, 7})); + n = m.erase(4); + assert(n == 0); + assert(m == make({2, 5, 6, 7})); + n = m.erase(6); + assert(n == 1); + assert(m == make({2, 5, 7})); + n = m.erase(7); + assert(n == 1); + assert(m == make({2, 5})); + n = m.erase(2); + assert(n == 1); + assert(m == make({5})); + n = m.erase(5); + assert(n == 1); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test, std::greater<>>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp new file mode 100644 index 00000000000000..cbf7cac603806d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(K&& k); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanErase = requires(M m, Transparent k) { m.erase(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanErase); +static_assert(!CanErase); +static_assert(!CanErase); +static_assert(!CanErase); + +template +struct HeterogeneousKey { + explicit HeterogeneousKey(Key key, It it) : key_(key), it_(it) {} + operator It() && { return it_; } + auto operator<=>(Key key) const { return key_ <=> key; } + friend bool operator<(const HeterogeneousKey&, const HeterogeneousKey&) { + assert(false); + return false; + } + Key key_; + It it_; +}; + +template +void test_simple() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(3); // erase(K&&) [with K=int] + assert(n == 1); + assert((m == M{1, 2, 4})); + typename M::key_type lvalue = 2; + n = m.erase(lvalue); // erase(K&&) [with K=int&] + assert(n == 1); + assert((m == M{1, 4})); + const typename M::key_type const_lvalue = 1; + n = m.erase(const_lvalue); // erase(const key_type&) + assert(n == 1); + assert((m == M{4})); +} + +template +void test_transparent_comparator() { + using M = std::flat_set; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.erase(Transparent{"abc"})), typename M::size_type); + + auto n = m.erase(Transparent{"epsilon"}); + assert(n == 1); + + M expected = {"alpha", "beta", "eta", "gamma"}; + assert(m == expected); + + auto n2 = m.erase(Transparent{"aaa"}); + assert(n2 == 0); + assert(m == expected); +} + +int main(int, char**) { + test_simple>(); + test_simple>(); + test_simple>(); + test_simple>>(); + + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>>(); + + { + // P2077's HeterogeneousKey example + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.erase(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp new file mode 100644 index 00000000000000..c3bbffabb90a08 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// containers extract() &&; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanExtract = requires(T&& t) { std::forward(t).extract(); }; + +static_assert(CanExtract&&>); +static_assert(!CanExtract&>); +static_assert(!CanExtract const&>); +static_assert(!CanExtract const&&>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + M m = M({1, 2, 3}); + + std::same_as auto keys = std::move(m).extract(); + + auto expected_keys = {1, 2, 3}; + assert(std::ranges::equal(keys, expected_keys)); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // extracted object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m = M({1, 2, 3}); + std::same_as auto keys = std::move(m).extract(); + assert(keys.size() == 3); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); + } + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + auto c = std::move(m).extract(); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we try to erase the key after value emplacement failure. + // and after erasure failure, we clear the flat_set + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp new file mode 100644 index 00000000000000..c0ddadc3006987 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair insert(const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using VT = typename M::value_type; + M m; + + const VT v1(2); + std::same_as decltype(auto) r = m.insert(v1); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + + const VT v2(1); + r = m.insert(v2); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == 1); + + const VT v3(3); + r = m.insert(v3); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); + + const VT v4(3); + r = m.insert(v4); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp new file mode 100644 index 00000000000000..7381514a70eabb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; + + M m = {1,1,1,3,3,3}; + m.insert({ + 4, + 4, + 4, + 1, + 1, + 1, + 2, + 2, + 2, + }); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(*m.begin() == V(1)); + assert(*std::next(m.begin()) == V(2)); + assert(*std::next(m.begin(), 2) == V(3)); + assert(*std::next(m.begin(), 3) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp new file mode 100644 index 00000000000000..c343d53a62215a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator insert(const_iterator position, const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = typename M::iterator; + using VT = typename M::value_type; + + M m; + const VT v1(2); + std::same_as decltype(auto) r = m.insert(m.end(), v1); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + + const VT v2(1); + r = m.insert(m.end(), v2); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == 1); + + const VT v3(3); + r = m.insert(m.end(), v3); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); + + const VT v4(3); + r = m.insert(m.end(), v4); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp new file mode 100644 index 00000000000000..d20a8ef8fdd92d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + + int ar1[] = { + 2, + 2, + 2, + 1, + 1, + 1, + 3, + 3, + 3, + }; + int ar2[] = { + 4, + 4, + 4, + 1, + 1, + 1, + 0, + 0, + 0, + }; + + M m; + m.insert(cpp17_input_iterator(ar1), cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(cpp17_input_iterator(ar2), cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp new file mode 100644 index 00000000000000..84b6c7fc1d34f6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// +// iterator insert(const_iterator position, value_type&&); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "../helpers.h" +#include "test_macros.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + using R = typename M::iterator; + M m; + std::same_as decltype(auto) r = m.insert(m.end(), V(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == V(2)); + + r = m.insert(m.end(), V(1)); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == V(1)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp new file mode 100644 index 00000000000000..536307252c6405 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// void insert_range(R&& rg); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "MoveOnly.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint container-compatible-range +template +concept CanInsertRange = requires(M m, R&& r) { m.insert_range(std::forward(r)); }; + +using Set = std::flat_set; + +static_assert(CanInsertRange>); +static_assert(CanInsertRange>); +static_assert(!CanInsertRange*>>); +static_assert(!CanInsertRange*>>); + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using M = std::flat_set, KeyContainer>; + using It = forward_iterator; + M m = {10, 8, 5, 2, 1}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), It(ar + 6)}; + static_assert(std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9, 10})); + } + { + using M = std::flat_set, KeyContainer>; + using It = cpp20_input_iterator; + M m = {8, 5, 3, 2}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), sentinel_wrapper(It(ar + 6))}; + static_assert(!std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9})); + } + { + // The "uniquing" part uses the comparator, not operator==. + struct ModTen { + bool operator()(int a, int b) const { return (a % 10) < (b % 10); } + }; + using M = std::flat_set; + M m = {21, 43, 15, 37}; + int ar[] = {33, 18, 55, 18, 42}; + m.insert_range(ar); + assert((m == M{21, 42, 43, 15, 37, 18})); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // Items are forwarded correctly from the input range (P2767). + MoveOnly a[] = {3, 1, 4, 1, 5}; + std::flat_set m; + m.insert_range(a | std::views::as_rvalue); + MoveOnly expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + // The element type of the range doesn't need to be std::pair (P2767). + int pa[] = {3, 1, 4, 1, 5}; + std::deque> a(pa, pa + 5); + std::flat_set m; + m.insert_range(a); + int expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp new file mode 100644 index 00000000000000..7d95f0521eb1f6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// pair insert( value_type&& v); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + using R = std::pair; + using V = typename M::value_type; + + M m; + std::same_as decltype(auto) r = m.insert(V(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == V(2)); + + r = m.insert(V(1)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == V(1)); + + r = m.insert(V(3)); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); + + r = m.insert(V(3)); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp new file mode 100644 index 00000000000000..fa5bf86830daec --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(sorted_unique_t, initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + M m = {1, 1, 1, 3, 3, 3}; + m.insert(std::sorted_unique, {0, 1, 2, 4}); + assert(m.size() == 5); + assert(std::distance(m.begin(), m.end()) == 5); + assert(*m.begin() == V(0)); + assert(*std::next(m.begin()) == V(1)); + assert(*std::next(m.begin(), 2) == V(2)); + assert(*std::next(m.begin(), 3) == V(3)); + assert(*std::next(m.begin(), 4) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp new file mode 100644 index 00000000000000..ef7b8391cee33c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(sorted_unique_t, InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + int ar1[] = {1, 2, 3}; + + int ar2[] = {0, 2, 4}; + + M m; + m.insert(std::sorted_unique, + cpp17_input_iterator(ar1), + cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(std::sorted_unique, + cpp17_input_iterator(ar2), + cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp new file mode 100644 index 00000000000000..72d7261a182547 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -0,0 +1,169 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair insert(P&& x); +// template iterator insert(const_iterator hint, P&& x); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// Constraints: is_constructible_v is true. +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; +using Iter = Set::const_iterator; + +static_assert(CanInsert); +static_assert(CanInsert); +static_assert(!CanInsert); +static_assert(!CanInsert); + +static int expensive_comparisons = 0; +static int cheap_comparisons = 0; + +struct CompareCounter { + int i_ = 0; + CompareCounter(int i) : i_(i) {} + friend auto operator<=>(const CompareCounter& x, const CompareCounter& y) { + expensive_comparisons += 1; + return x.i_ <=> y.i_; + } + bool operator==(const CompareCounter&) const = default; + friend auto operator<=>(const CompareCounter& x, int y) { + cheap_comparisons += 1; + return x.i_ <=> y; + } +}; + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + const int expected[] = {1, 2, 3, 4, 5}; + { + // insert(P&&) + // Unlike flat_set, here we can't use key_compare to compare value_type versus P, + // so we must eagerly convert to value_type. + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, P&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // insert(value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens last + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // emplace(Args&&...) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.emplace(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // no ambiguity between insert(pos, P&&) and insert(first, last) + using M = std::flat_set; + struct Evil { + operator M::value_type() const; + operator M::const_iterator() const; + }; + std::flat_set m; + ASSERT_SAME_TYPE(decltype(m.insert(Evil())), std::pair); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); + } + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(t); + }; + test_emplace_exception_guarantee(insert_func); + } + { + auto insert_func_iter = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(m.begin(), t); + }; + test_emplace_exception_guarantee(insert_func_iter); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp new file mode 100644 index 00000000000000..49cb6eb6163c90 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void replace(container_type&& key_cont); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanReplace = requires(T t, Args&&... args) { t.replace(std::forward(args)...); }; + +using Set = std::flat_set; +static_assert(CanReplace>); +static_assert(!CanReplace&>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = M({1, 2, 3}); + KeyContainer new_keys = {7, 8}; + auto expected_keys = new_keys; + m.replace(std::move(new_keys)); + assert(m.size() == 2); + assert(std::ranges::equal(m, expected_keys)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp new file mode 100644 index 00000000000000..23a2dc85989bb7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// `check_assertion.h` requires Unix headers and regex support. +// REQUIRES: has-unix-headers +// UNSUPPORTED: no-localization +// UNSUPPORTED: no-exceptions + +// + +// void swap(flat_set& y) noexcept; +// friend void swap(flat_set& x, flat_set& y) noexcept + +// Test that std::terminate is called if any exception is thrown during swap + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../helpers.h" +#include "check_assertion.h" + +template +void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) { + { + // key swap throws + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m1, m2; + m1.emplace(1); + m1.emplace(2); + m2.emplace(3); + m2.emplace(4); + // swap is noexcept + EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); }); + } +} + +int main(int, char**) { + { + auto swap_func = [](auto& m1, auto& m2) { swap(m1, m2); }; + test_swap_exception_guarantee(swap_func); + } + + { + auto swap_func = [](auto& m1, auto& m2) { m1.swap(m2); }; + test_swap_exception_guarantee(swap_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp new file mode 100644 index 00000000000000..bc7baa67e52a59 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend void swap(flat_set& x, flat_set& y) noexcept + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptAdlSwap = requires(T t1, T t2) { + { swap(t1, t2) } noexcept; +}; + +static_assert(NoExceptAdlSwap>); + +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptAdlSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp new file mode 100644 index 00000000000000..b0b06a9499efc7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void swap(flat_set& y) noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptMemberSwap = requires(T t1, T t2) { + { t1.swap(t2) } noexcept; +}; + +static_assert(NoExceptMemberSwap>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptMemberSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp new file mode 100644 index 00000000000000..971b5e1c338dd1 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// key_compare key_comp() const; +// value_compare value_comp() const; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + { + using M = std::flat_set; + using Comp = std::less; // the default + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + { + using Comp = std::function; + using M = std::flat_set; + Comp comp = std::greater(); + M m({}, comp); + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(!kc(1, 2)); + assert(kc(2, 1)); + auto vc = m.value_comp(); + assert(!vc(1, 2)); + assert(vc(2, 1)); + } + { + using Comp = std::less<>; + using M = std::flat_set; + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + auto a = std::make_pair(1, 2); + ASSERT_SAME_TYPE(decltype(vc(a, a)), bool); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp new file mode 100644 index 00000000000000..b14da66f611301 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// bool contains(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp new file mode 100644 index 00000000000000..507560608952b0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template bool contains(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanContains = requires(M m, Transparent k) { m.contains(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanContains); +static_assert(CanContains); +static_assert(!CanContains); +static_assert(!CanContains); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.contains(Transparent{"abc"})), bool); + ASSERT_SAME_TYPE(decltype(std::as_const(m).contains(Transparent{"b"})), bool); + assert(m.contains(Transparent{"alpha"}) == true); + assert(m.contains(Transparent{"beta"}) == true); + assert(m.contains(Transparent{"epsilon"}) == true); + assert(m.contains(Transparent{"eta"}) == true); + assert(m.contains(Transparent{"gamma"}) == true); + assert(m.contains(Transparent{"al"}) == false); + assert(m.contains(Transparent{""}) == false); + assert(m.contains(Transparent{"g"}) == false); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto b = m.contains(Transparent{3}); + assert(b); + assert(transparent_used); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp new file mode 100644 index 00000000000000..478f615358b606 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type count(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using S = typename KeyContainer::size_type; + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp new file mode 100644 index 00000000000000..b591258f74399c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template size_type count(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanCount = requires(M m, Transparent k) { m.count(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanCount); +static_assert(CanCount); +static_assert(!CanCount); +static_assert(!CanCount); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.count(Transparent{"abc"})), typename M::size_type); + ASSERT_SAME_TYPE(decltype(std::as_const(m).count(Transparent{"b"})), typename M::size_type); + assert(m.count(Transparent{"alpha"}) == 1); + assert(m.count(Transparent{"beta"}) == 1); + assert(m.count(Transparent{"epsilon"}) == 1); + assert(m.count(Transparent{"eta"}) == 1); + assert(m.count(Transparent{"gamma"}) == 1); + assert(m.count(Transparent{"al"}) == 0); + assert(m.count(Transparent{""}) == 0); + assert(m.count(Transparent{"g"}) == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.count(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp new file mode 100644 index 00000000000000..a088b7fee17d2c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair equal_range(const key_type& k); +// pair equal_range(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin, begin)); + assert(m.equal_range(1) == std::pair(begin, begin + 1)); + assert(m.equal_range(2) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(3) == std::pair(begin + 2, begin + 2)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(6) == std::pair(begin + 4, begin + 4)); + assert(m.equal_range(7) == std::pair(begin + 4, begin + 4)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin() + 4, m.cbegin() + 5)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin() + 5, m.cbegin() + 5)); + } + + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin + 5, begin + 5)); + assert(m.equal_range(1) == std::pair(begin + 4, begin + 5)); + assert(m.equal_range(2) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(3) == std::pair(begin + 3, begin + 3)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(6) == std::pair(begin + 1, begin + 1)); + assert(m.equal_range(7) == std::pair(begin + 1, begin + 1)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin(), m.cbegin() + 1)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin(), m.cbegin())); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp new file mode 100644 index 00000000000000..ede5d91e19b9fd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair equal_range(const K& x); +// template pair equal_range(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanEqualRange = requires(M m, Transparent k) { m.equal_range(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanEqualRange); +static_assert(CanEqualRange); +static_assert(!CanEqualRange); +static_assert(!CanEqualRange); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + using R = std::pair; + using CR = std::pair; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.equal_range(Transparent{"abc"})), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(Transparent{"b"})), CR); + + auto test_found = [&](auto&& map, const std::string& expected_key) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(last - first == 1); + assert(*first == expected_key); + }; + + auto test_not_found = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(first == last); + assert(first - m.begin() == expected_offset); + }; + + test_found(m, "alpha"); + test_found(m, "beta"); + test_found(m, "epsilon"); + test_found(m, "eta"); + test_found(m, "gamma"); + test_found(cm, "alpha"); + test_found(cm, "beta"); + test_found(cm, "epsilon"); + test_found(cm, "eta"); + test_found(cm, "gamma"); + + test_not_found(m, "charlie", 2); + test_not_found(m, "aaa", 0); + test_not_found(m, "zzz", 5); + test_not_found(cm, "charlie", 2); + test_not_found(cm, "aaa", 0); + test_not_found(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto p = m.equal_range(Transparent{3}); + assert(p.first != p.second); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp new file mode 100644 index 00000000000000..cf0dd2d1dd831c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator find(const key_type& k); +// const_iterator find(const key_type& k) const; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.find(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(0)), typename M::const_iterator); + assert(m.find(0) == m.end()); + assert(m.find(1) == m.begin()); + assert(m.find(2) == m.begin() + 1); + assert(m.find(3) == m.end()); + assert(m.find(4) == m.begin() + 2); + assert(m.find(5) == m.begin() + 3); + assert(m.find(6) == m.end()); + assert(m.find(7) == m.end()); + assert(std::as_const(m).find(8) == m.begin() + 4); + assert(std::as_const(m).find(9) == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp new file mode 100644 index 00000000000000..730a57b0a6cb85 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator find(const K& x); +// template const_iterator find(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanFind = requires(M m, Transparent k) { m.find(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanFind); +static_assert(CanFind); +static_assert(!CanFind); +static_assert(!CanFind); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.find(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(Transparent{"b"})), typename M::const_iterator); + + auto test_find = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.find(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_find(m, "alpha", 0); + test_find(m, "beta", 1); + test_find(m, "epsilon", 2); + test_find(m, "eta", 3); + test_find(m, "gamma", 4); + test_find(m, "charlie", 5); + test_find(m, "aaa", 5); + test_find(m, "zzz", 5); + test_find(cm, "alpha", 0); + test_find(cm, "beta", 1); + test_find(cm, "epsilon", 2); + test_find(cm, "eta", 3); + test_find(cm, "gamma", 4); + test_find(cm, "charlie", 5); + test_find(cm, "aaa", 5); + test_find(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.find(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp new file mode 100644 index 00000000000000..093c32e537ed35 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator lower_bound(const key_type& k); +// const_iterator lower_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.begin()); + assert(m.lower_bound(1) == m.begin()); + assert(m.lower_bound(2) == m.begin() + 1); + assert(m.lower_bound(3) == m.begin() + 2); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 3); + assert(m.lower_bound(6) == m.begin() + 4); + assert(m.lower_bound(7) == m.begin() + 4); + assert(std::as_const(m).lower_bound(8) == m.begin() + 4); + assert(std::as_const(m).lower_bound(9) == m.end()); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.end()); + assert(m.lower_bound(1) == m.begin() + 4); + assert(m.lower_bound(2) == m.begin() + 3); + assert(m.lower_bound(3) == m.begin() + 3); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 1); + assert(m.lower_bound(6) == m.begin() + 1); + assert(m.lower_bound(7) == m.begin() + 1); + assert(std::as_const(m).lower_bound(8) == m.begin()); + assert(std::as_const(m).lower_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp new file mode 100644 index 00000000000000..18f9bc6dd32955 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator lower_bound(const K& x); +// template const_iterator lower_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanLowerBound = requires(M m, Transparent k) { m.lower_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanLowerBound); +static_assert(CanLowerBound); +static_assert(!CanLowerBound); +static_assert(!CanLowerBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_lower_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.lower_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_lower_bound(m, "abc", 0); + test_lower_bound(m, "alpha", 0); + test_lower_bound(m, "beta", 1); + test_lower_bound(m, "bets", 2); + test_lower_bound(m, "charlie", 2); + test_lower_bound(m, "echo", 2); + test_lower_bound(m, "epsilon", 2); + test_lower_bound(m, "eta", 3); + test_lower_bound(m, "gamma", 4); + test_lower_bound(m, "golf", 5); + test_lower_bound(m, "zzz", 5); + + test_lower_bound(cm, "abc", 0); + test_lower_bound(cm, "alpha", 0); + test_lower_bound(cm, "beta", 1); + test_lower_bound(cm, "bets", 2); + test_lower_bound(cm, "charlie", 2); + test_lower_bound(cm, "echo", 2); + test_lower_bound(cm, "epsilon", 2); + test_lower_bound(cm, "eta", 3); + test_lower_bound(cm, "gamma", 4); + test_lower_bound(cm, "golf", 5); + test_lower_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.lower_bound(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp new file mode 100644 index 00000000000000..ab34de85103175 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator upper_bound(const key_type& k); +// const_iterator upper_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.begin()); + assert(m.upper_bound(1) == m.begin() + 1); + assert(m.upper_bound(2) == m.begin() + 2); + assert(m.upper_bound(3) == m.begin() + 2); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 4); + assert(m.upper_bound(6) == m.begin() + 4); + assert(std::as_const(m).upper_bound(7) == m.begin() + 4); + assert(std::as_const(m).upper_bound(8) == m.end()); + assert(std::as_const(m).upper_bound(9) == m.end()); + } + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.end()); + assert(m.upper_bound(1) == m.end()); + assert(m.upper_bound(2) == m.begin() + 4); + assert(m.upper_bound(3) == m.begin() + 3); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 2); + assert(m.upper_bound(6) == m.begin() + 1); + assert(m.upper_bound(7) == m.begin() + 1); + assert(std::as_const(m).upper_bound(8) == m.begin() + 1); + assert(std::as_const(m).upper_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp new file mode 100644 index 00000000000000..69ce2ae926a305 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator upper_bound(const K& x); +// template const_iterator upper_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanUpperBound = requires(M m, Transparent k) { m.upper_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanUpperBound); +static_assert(CanUpperBound); +static_assert(!CanUpperBound); +static_assert(!CanUpperBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_upper_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.upper_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_upper_bound(m, "abc", 0); + test_upper_bound(m, "alpha", 1); + test_upper_bound(m, "beta", 2); + test_upper_bound(m, "bets", 2); + test_upper_bound(m, "charlie", 2); + test_upper_bound(m, "echo", 2); + test_upper_bound(m, "epsilon", 3); + test_upper_bound(m, "eta", 4); + test_upper_bound(m, "gamma", 5); + test_upper_bound(m, "golf", 5); + test_upper_bound(m, "zzz", 5); + + test_upper_bound(cm, "abc", 0); + test_upper_bound(cm, "alpha", 1); + test_upper_bound(cm, "beta", 2); + test_upper_bound(cm, "bets", 2); + test_upper_bound(cm, "charlie", 2); + test_upper_bound(cm, "echo", 2); + test_upper_bound(cm, "epsilon", 3); + test_upper_bound(cm, "eta", 4); + test_upper_bound(cm, "gamma", 5); + test_upper_bound(cm, "golf", 5); + test_upper_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.upper_bound(Transparent{2}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h new file mode 100644 index 00000000000000..9fff262d84234e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -0,0 +1,294 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_flat_set_HELPERS_H +#define SUPPORT_flat_set_HELPERS_H + +#include +#include +#include +#include +#include + +#include "test_allocator.h" +#include "test_macros.h" + +template +void check_invariant(const std::flat_set& m) { + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); + auto key_equal = [&](const auto& x, const auto& y) { + const auto& c = m.key_comp(); + return !c(x, y) && !c(y, x); + }; + assert(std::adjacent_find(m.begin(), m.end(), key_equal) == m.end()); +} + +struct StartsWith { + explicit StartsWith(char ch) : lower_(1, ch), upper_(1, ch + 1) {} + StartsWith(const StartsWith&) = delete; + void operator=(const StartsWith&) = delete; + struct Less { + using is_transparent = void; + bool operator()(const std::string& a, const std::string& b) const { return a < b; } + bool operator()(const StartsWith& a, const std::string& b) const { return a.upper_ <= b; } + bool operator()(const std::string& a, const StartsWith& b) const { return a < b.lower_; } + bool operator()(const StartsWith&, const StartsWith&) const { + assert(false); // should not be called + return false; + } + }; + +private: + std::string lower_; + std::string upper_; +}; + +template +struct CopyOnlyVector : std::vector { + using std::vector::vector; + + CopyOnlyVector(const CopyOnlyVector&) = default; + CopyOnlyVector(CopyOnlyVector&& other) : CopyOnlyVector(other) {} + CopyOnlyVector(CopyOnlyVector&& other, std::vector::allocator_type alloc) : CopyOnlyVector(other, alloc) {} + + CopyOnlyVector& operator=(const CopyOnlyVector&) = default; + CopyOnlyVector& operator=(CopyOnlyVector& other) { return this->operator=(other); } +}; + +template +struct Transparent { + T t; + + operator T() const + requires ConvertibleToT + { + return t; + } +}; + +template +using ConvertibleTransparent = Transparent; + +template +using NonConvertibleTransparent = Transparent; + +struct TransparentComparator { + using is_transparent = void; + + bool* transparent_used = nullptr; + TransparentComparator() = default; + TransparentComparator(bool& used) : transparent_used(&used) {} + + template + bool operator()(const T& t, const Transparent& transparent) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return t < transparent.t; + } + + template + bool operator()(const Transparent& transparent, const T& t) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return transparent.t < t; + } + + template + bool operator()(const T& t1, const T& t2) const { + return t1 < t2; + } +}; + +struct NonTransparentComparator { + template + bool operator()(const T&, const Transparent&) const; + + template + bool operator()(const Transparent&, const T&) const; + + template + bool operator()(const T&, const T&) const; +}; + +struct NoDefaultCtr { + NoDefaultCtr() = delete; +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +struct EmplaceUnsafeContainer : std::vector { + using std::vector::vector; + + template + auto emplace(Args&&... args) -> decltype(std::declval>().emplace(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } + + template + auto insert(Args&&... args) -> decltype(std::declval>().insert(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } +}; + +template +struct ThrowOnEraseContainer : std::vector { + using std::vector::vector; + + template + auto erase(Args&&... args) -> decltype(std::declval>().erase(std::forward(args)...)) { + throw 42; + } +}; + +template +struct ThrowOnMoveContainer : std::vector { + using std::vector::vector; + + ThrowOnMoveContainer(ThrowOnMoveContainer&&) { throw 42; } + + ThrowOnMoveContainer& operator=(ThrowOnMoveContainer&&) { throw 42; } +}; + +#endif + +template +void test_emplace_exception_guarantee([[maybe_unused]] F&& emplace_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using C = TransparentComparator; + { + // Throw on emplace the key, and underlying has strong exception guarantee + using KeyContainer = std::vector>; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + + test_allocator_statistics stats; + + KeyContainer a({1, 2, 3, 4}, test_allocator{&stats}); + [[maybe_unused]] auto expected_keys = a; + M m(std::sorted_unique, std::move(a)); + + stats.throw_after = 1; + try { + emplace_function(m, 0); + assert(false); + } catch (const std::bad_alloc&) { + check_invariant(m); + // In libc++, the flat_set is unchanged + LIBCPP_ASSERT(m.size() == 4); + LIBCPP_ASSERT(std::ranges::equal(m, expected_keys)); + } + } + { + // Throw on emplace the key, and underlying has no strong exception guarantee + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(!std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + KeyContainer a = {1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + emplace_function(m, 0); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, the flat_set is cleared + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} + +template +void test_insert_range_exception_guarantee([[maybe_unused]] F&& insert_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + test_allocator_statistics stats; + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + + std::vector newValues = {0, 1, 5, 6, 7, 8}; + stats.throw_after = 1; + try { + insert_function(m, newValues); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when inserting a range + LIBCPP_ASSERT(m.size() == 0); + } +#endif +} + +template +void test_erase_exception_guarantee([[maybe_unused]] F&& erase_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + { + // key erase throws + using KeyContainer = ThrowOnEraseContainer; + using M = std::flat_set; + + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + erase_function(m, 3); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when erasing + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} +class Moveable { + int int_; + double double_; + +public: + Moveable() : int_(0), double_(0) {} + Moveable(int i, double d) : int_(i), double_(d) {} + Moveable(Moveable&& x) : int_(x.int_), double_(x.double_) { + x.int_ = -1; + x.double_ = -1; + } + Moveable& operator=(Moveable&& x) { + int_ = x.int_; + x.int_ = -1; + double_ = x.double_; + x.double_ = -1; + return *this; + } + + Moveable(const Moveable&) = delete; + Moveable& operator=(const Moveable&) = delete; + bool operator==(const Moveable& x) const { return int_ == x.int_ && double_ == x.double_; } + bool operator<(const Moveable& x) const { return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_); } + + int get() const { return int_; } + bool moved() const { return int_ == -1; } +}; + +#endif // SUPPORT_flat_set_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp new file mode 100644 index 00000000000000..c4a9810016536b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Check that std::flat_set and its iterators can be instantiated with an incomplete +// type. + +#include +#include + +struct A { + using Set = std::flat_set; + int data; + Set m; + Set::iterator it; + Set::const_iterator cit; +}; + +// Implement the operator< required in order to instantiate flat_set +bool operator<(A const& L, A const& R) { return L.data < R.data; } + +int main(int, char**) { + A a; + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp new file mode 100644 index 00000000000000..f6d08bb736d300 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend bool operator==(const flat_set& x, const flat_set& y); +// friend synth-three-way-result +// operator<=>(const flat_set& x, const flat_set& y); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_comparisons.h" +#include "test_container_comparisons.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, true)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } + { + // Comparisons use value_type's native operators, not the comparator + using C = std::flat_set>; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, false)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = C(std::sorted_unique, {std::numeric_limits::quiet_NaN()}); + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + } + { + // Comparisons use value_type's native operators, not the comparator + struct StrongComp { + bool operator()(double a, double b) const { return std::strong_order(a, b) < 0; } + }; + using C = std::flat_set; + C s1 = {1}; + C s2 = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + s1 = {1, std::numeric_limits::quiet_NaN(), 1}; + s2 = {std::numeric_limits::quiet_NaN(), 1}; + assert(std::lexicographical_compare_three_way(s1.begin(), s1.end(), s2.begin(), s2.end(), std::strong_order) == + std::strong_ordering::equal); + assert(s1 != s2); + assert((s1 <=> s2) == std::partial_ordering::unordered); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp new file mode 100644 index 00000000000000..a845b2b81e89d3 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// using key_type = Key; +// using value_type = Key; +// using key_compare = Compare; +// using value_compare = Compare; +// using reference = value_type&; +// using const_reference = const value_type&; +// using size_type = typename KeyContainer::size_type; +// using difference_type = typename KeyContainer::difference_type; +// using iterator = implementation-defined; // see [container.requirements] +// using const_iterator = implementation-defined; // see [container.requirements] +// using reverse_iterator = std::reverse_iterator; +// using const_reverse_iterator = std::reverse_iterator; +// using container_type = KeyContainer; + +#include +#include +#include +#include +#include +#include +#include +#include "min_allocator.h" + +void test() { + { + using M = std::flat_set; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(requires { typename M::value_compare; }); + } + + { + struct A {}; + struct Compare { + bool operator()(const std::string&, const std::string&) const; + }; + using M = std::flat_set>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + } + { + using C = std::flat_set, std::deque>>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + // size_type is invariably size_t + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>>); + } +} >From 96903d9c8f1ea42de65fbe1a07e59413a1630d1e Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 13:21:24 +0000 Subject: [PATCH 2/8] review --- libcxx/include/__flat_set/flat_set.h | 137 +++---- .../flat.set/flat.set.capacity/empty.pass.cpp | 14 +- .../flat.set.capacity/max_size.pass.cpp | 8 +- .../flat.set/flat.set.capacity/size.pass.cpp | 14 +- .../flat.set/flat.set.cons/alloc.pass.cpp | 6 +- .../assign_initializer_list.pass.cpp | 19 +- .../flat.set/flat.set.cons/compare.pass.cpp | 6 +- .../flat.set.cons/containers.pass.cpp | 25 +- .../flat.set/flat.set.cons/copy.pass.cpp | 6 +- .../flat.set.cons/copy_alloc.pass.cpp | 6 +- .../copy_assign.addressof.compile.pass.cpp | 30 -- .../flat.set.cons/copy_assign.pass.cpp | 17 +- .../flat.set/flat.set.cons/deduct.pass.cpp | 353 +++++++++--------- .../flat.set/flat.set.cons/default.pass.cpp | 36 +- .../flat.set.cons/default_noexcept.pass.cpp | 58 --- .../flat.set.cons/dtor_noexcept.pass.cpp | 6 +- .../flat.set.cons/initializer_list.pass.cpp | 6 +- .../flat.set/flat.set.cons/iter_iter.pass.cpp | 6 +- .../flat.set/flat.set.cons/move.pass.cpp | 107 +++++- .../flat.set.cons/move_alloc.pass.cpp | 10 +- .../flat.set.cons/move_assign.pass.cpp | 141 ++++++- .../flat.set.cons/move_assign_clears.pass.cpp | 101 ----- .../move_assign_noexcept.pass.cpp | 85 ----- .../flat.set.cons/move_exceptions.pass.cpp | 58 --- .../flat.set.cons/move_noexcept.pass.cpp | 94 ----- .../flat.set/flat.set.cons/pmr.pass.cpp | 6 +- .../flat.set/flat.set.cons/range.pass.cpp | 6 +- .../flat.set.cons/sorted_container.pass.cpp | 6 +- .../sorted_initializer_list.pass.cpp | 10 +- .../flat.set.cons/sorted_iter_iter.pass.cpp | 6 +- .../flat.set.erasure/erase_if.pass.cpp | 20 +- .../erase_if_exceptions.pass.cpp | 7 +- .../flat.set.iterators/iterator.pass.cpp | 18 +- .../iterator_comparison.pass.cpp | 14 +- .../reverse_iterator.pass.cpp | 8 +- .../flat.set.modifiers/clear.pass.cpp | 18 +- .../flat.set.modifiers/emplace.pass.cpp | 25 +- .../flat.set.modifiers/emplace_hint.pass.cpp | 25 +- .../flat.set.modifiers/erase_iter.pass.cpp | 25 +- .../erase_iter_iter.pass.cpp | 24 +- .../flat.set.modifiers/erase_key.pass.cpp | 37 +- .../erase_key_transparent.pass.cpp | 34 +- .../flat.set.modifiers/extract.pass.cpp | 21 +- .../flat.set.modifiers/insert_cv.pass.cpp | 33 +- .../insert_initializer_list.pass.cpp | 42 ++- .../insert_iter_cv.pass.cpp | 23 +- .../insert_iter_iter.pass.cpp | 27 +- .../insert_iter_rv.pass.cpp | 43 ++- .../flat.set.modifiers/insert_range.pass.cpp | 38 +- .../flat.set.modifiers/insert_rv.pass.cpp | 42 ++- .../insert_sorted_initializer_list.pass.cpp | 35 +- .../insert_sorted_iter_iter.pass.cpp | 29 +- .../insert_transparent.pass.cpp | 21 +- .../flat.set.modifiers/replace.pass.cpp | 50 +-- .../flat.set.modifiers/swap_free.pass.cpp | 16 +- .../flat.set.modifiers/swap_member.pass.cpp | 14 +- .../flat.set/flat.set.observers/comp.pass.cpp | 6 +- .../flat.set.operations/contains.pass.cpp | 14 +- .../contains_transparent.pass.cpp | 17 +- .../flat.set.operations/count.pass.cpp | 14 +- .../count_transparent.pass.cpp | 16 +- .../flat.set.operations/equal_range.pass.cpp | 14 +- .../equal_range_transparent.pass.cpp | 16 +- .../flat.set.operations/find.pass.cpp | 14 +- .../find_transparent.pass.cpp | 16 +- .../flat.set.operations/lower_bound.pass.cpp | 14 +- .../lower_bound_transparent.pass.cpp | 16 +- .../flat.set.operations/upper_bound.pass.cpp | 14 +- .../upper_bound_transparent.pass.cpp | 17 +- .../container.adaptors/flat.set/helpers.h | 19 +- .../flat.set/incomplete_type.pass.cpp | 5 +- .../flat.set/op_compare.pass.cpp | 17 +- 72 files changed, 1214 insertions(+), 1087 deletions(-) delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index c920632c453bf5..37e4c9f7c686b0 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP___FLAT_set_FLAT_SET_H -#define _LIBCPP___FLAT_set_FLAT_SET_H +#ifndef _LIBCPP___FLAT_SET_FLAT_SET_H +#define _LIBCPP___FLAT_SET_FLAT_SET_H #include <__algorithm/lexicographical_compare_three_way.h> #include <__algorithm/min.h> @@ -99,13 +99,6 @@ class flat_set { using const_reverse_iterator = std::reverse_iterator; using container_type = _KeyContainer; -private: - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = - uses_allocator::value; - - _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; - public: // [flat.set.cons], construct/copy/destroy _LIBCPP_HIDE_FROM_ABI @@ -178,31 +171,31 @@ class flat_set { : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( @@ -210,7 +203,7 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { @@ -219,12 +212,12 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) # if _LIBCPP_HAS_EXCEPTIONS try @@ -239,14 +232,14 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert(__first, __last); } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { @@ -254,7 +247,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { @@ -262,7 +255,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, @@ -274,37 +267,37 @@ class flat_set { } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert_range(std::forward<_Range>(__rg)); } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { insert_range(std::forward<_Range>(__rg)); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} @@ -334,11 +327,8 @@ class flat_set { // iterators _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } @@ -382,7 +372,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { return emplace(std::forward<_Kp>(__x)); } @@ -395,7 +385,7 @@ class flat_set { } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { return emplace_hint(__hint, std::forward<_Kp>(__x)); } @@ -425,7 +415,7 @@ class flat_set { __reserve(ranges::size(__range)); } - __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + __append_sort_merge_unique(std::forward<_Range>(__range)); } _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } @@ -468,7 +458,7 @@ class flat_set { } template - requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> && !is_convertible_v<_Kp &&, const_iterator>) _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { auto [__first, __last] = equal_range(__x); @@ -505,13 +495,13 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { return __find_impl(*this, __x); } @@ -519,7 +509,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { return contains(__x) ? 1 : 0; } @@ -527,7 +517,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { return find(__x) != end(); } @@ -541,13 +531,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { return ranges::lower_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { return ranges::lower_bound(__keys_, __x, __compare_); } @@ -561,13 +551,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { return ranges::upper_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { return ranges::upper_bound(__keys_, __x, __compare_); } @@ -581,12 +571,12 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { return __equal_range_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { return __equal_range_impl(*this, __x); } @@ -611,14 +601,14 @@ class flat_set { }; template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), __compare_(std::forward<_CompArg>(__comp)...) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc)), __compare_(std::forward<_CompArg>(__comp)...) {} @@ -637,17 +627,30 @@ class flat_set { __keys_.erase(__dup_start, __keys_.end()); } - template - _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { - auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); - size_type __old_size = size(); - if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { - __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + template + _LIBCPP_HIDE_FROM_ABI void __append(_InputIterator __first, _InputIterator __last) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append(_Range&& __rng) { + if constexpr (requires { __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); }) { + // C++23 Sequence Container should have insert_range member function + __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); + } else if constexpr (ranges::common_range<_Range>) { + __keys_.insert(__keys_.end(), ranges::begin(__rng), ranges::end(__rng)); } else { - for (; __first != __last; ++__first) { - __keys_.insert(__keys_.end(), *__first); + for (auto&& __x : __rng) { + __keys_.insert(__keys_.end(), std::forward(__x)); } } + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_Args&&... __args) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + __append(std::forward<_Args>(__args)...); if (size() != __old_size) { if constexpr (!_WasSorted) { ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); @@ -831,18 +834,18 @@ template struct uses_allocator, _Allocator> : bool_constant> {}; - template - _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type - erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { - auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); - auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { - return static_cast(__pred(e)); - }); - auto __res = __flat_set.__keys_.end() - __it; - __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); - __guard.__complete(); - return __res; - } +template +_LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type +erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; +} _LIBCPP_END_NAMESPACE_STD @@ -850,4 +853,4 @@ _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS -#endif // _LIBCPP___FLAT_set_FLAT_SET_H +#endif // _LIBCPP___FLAT_SET_FLAT_SET_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp index 204df1d681af1b..223b92fc3e8e84 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m; @@ -38,11 +38,15 @@ void test() { assert(m.empty()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index cd7f424e00ece2..0489d886257911 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -24,7 +24,8 @@ #include "test_allocator.h" #include "test_macros.h" -int main(int, char**) { +void test() { + { using A1 = limited_allocator; using C = std::flat_set, std::vector>; @@ -59,5 +60,10 @@ int main(int, char**) { assert(c.max_size() <= max_dist); assert(c.max_size() <= alloc_max_size(std::allocator())); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp index 7c156e95ecb1c8..9f5ffdd0663513 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; using S = typename M::size_type; { @@ -56,11 +56,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp index acc0817d7cac4d..d14e883dd5e936 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -22,7 +22,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -55,6 +55,10 @@ int main(int, char**) { auto v = std::move(m).extract(); assert(v.get_allocator().get_id() == 5); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7f75f1e1611e3b..7e948d7c5fe976 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -33,7 +33,6 @@ void test() { m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); - LIBCPP_ASSERT(std::ranges::equal(m, expected)); } { M m = {10, 8}; @@ -44,13 +43,17 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp index b3bee18f5a936b..110757a1bb9ab6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -78,6 +78,10 @@ int main(int, char**) { auto keys = std::move(m).extract(); assert(keys.get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp index 3d1e6240c952e8..6b1246885bf527 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -36,7 +36,7 @@ void conversion_test(T); template concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -116,21 +116,16 @@ int main(int, char**) { auto m = M(ks, A(4)); // replaces the allocators assert(!ks.empty()); // it was an lvalue above assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); + auto keys = M(m).extract(); assert(keys.get_allocator() == A(4)); - } - { - // flat_set(container_type , const Allocator&) + // explicit(false) - using A = test_allocator; - using M = std::flat_set, std::deque>; static_assert(ImplicitlyConstructible&, const A&>); - auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); - M m = {ks, A(4)}; // implicit ctor - assert(!ks.empty()); // it was an lvalue above - assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); - assert(keys.get_allocator() == A(4)); + M m2 = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert(m2 == m); + auto keys2 = std::move(m).extract(); + assert(keys2.get_allocator() == A(4)); } { // flat_set(container_type , key_compare, const Allocator&) @@ -153,6 +148,10 @@ int main(int, char**) { keys = std::move(m2).extract(); assert(keys.get_allocator() == A(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp index f1dbc955e1b0de..1ba550d98f01f6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -21,7 +21,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; std::vector> ks({1, 3, 5}, test_allocator(6)); @@ -59,6 +59,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == other_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp index 59fb9d0a38366f..5011bd20030641 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -23,7 +23,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -58,6 +58,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == test_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp deleted file mode 100644 index 169b469f3bca68..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp +++ /dev/null @@ -1,30 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(const flat_set& s); - -// Validate whether the container can be copy-assigned (move-assigned, swapped) -// with an ADL-hijacking operator& - -#include -#include - -#include "test_macros.h" -#include "operator_hijacker.h" - -void test() { - std::flat_set so; - std::flat_set s; - s = so; - s = std::move(so); - swap(s, so); -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp index cdd5045f4bb9f7..695363e3aeabab 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -17,11 +17,12 @@ #include #include +#include "operator_hijacker.h" #include "test_macros.h" #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // test_allocator is not propagated using C = test_less; @@ -81,5 +82,19 @@ int main(int, char**) { m = static_cast(m); assert((m == M{{1, 2}})); } + { + // Validate whether the container can be copy-assigned (move-assigned, swapped) + // with an ADL-hijacking operator& + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); + } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp index 612e64a7c42f23..607fe0d1a9713a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -26,24 +26,21 @@ #include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" -using P = std::pair; -using PC = std::pair; - void test_copy() { { - std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set source = {1, 2}; std::flat_set s(source); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s{source}; // braces instead of parens ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s(source, std::allocator()); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); @@ -52,275 +49,259 @@ void test_copy() { void test_containers() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); - std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + int expected[] = {1, 2, 3, INT_MAX}; { - std::flat_set s(ks, vs); + std::flat_set s(ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + std::flat_set s(std::sorted_unique, sorted_ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, test_allocator(0, 44)); + std::flat_set s(ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_containers_compare() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); - std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + int expected[] = {INT_MAX, 3, 2, 1}; { - std::flat_set s(ks, vs, std::greater()); + std::flat_set s(ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_iter_iter() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const int arr[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arr[] = {1, 2, 3, INT_MAX}; + const int arrc[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arrc[] = {1, 2, 3, INT_MAX}; { std::flat_set m(std::begin(arr), std::end(arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::begin(arrc), std::end(arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.begin(), mo.end()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.cbegin(), mo.cend()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); - } - { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); + // This does not deduce to flat_set(InputIterator, InputIterator) + // But deduces to flat_set(initializer_list) + int source[3] = {1, 2, 3}; + std::flat_set s = {source, source + 3}; + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 2); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + int source[3] = {1, 2, 3}; std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); assert(s.size() == 3); } } void test_iter_iter_compare() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m(std::begin(arr), std::end(arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::begin(arrc), std::end(arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set mo; - std::flat_set m(mo.begin(), mo.end(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } - { - std::flat_set mo; - std::flat_set m(mo.cbegin(), mo.cend(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } + // const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m(std::begin(arr), std::end(arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.begin(), mo.end(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.cbegin(), mo.cend(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } } void test_initializer_list() { - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - { - std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - } - { - using M = std::flat_set; - M m; - std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - assert(s[m] == m); - } + // const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + // { + // std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // } + // { + // using M = std::flat_set; + // M m; + // std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // assert(s[m] == m); + // } } void test_initializer_list_compare() { - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } } void test_from_range() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; - { - std::flat_set s(std::from_range, r); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + // { + // std::flat_set s(std::from_range, r); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } void test_from_range_compare() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; - { - std::flat_set s(std::from_range, r, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + // { + // std::flat_set s(std::from_range, r, std::greater()); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } int main(int, char**) { @@ -335,7 +316,7 @@ int main(int, char**) { test_from_range(); test_from_range_compare(); - AssociativeContainerDeductionGuidesSfinaeAway>(); + AssociativeContainerDeductionGuidesSfinaeAway>(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp index 64b0bfcb383a72..292af96c61582f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -19,9 +19,10 @@ #include #include -#include "test_macros.h" #include "min_allocator.h" +#include "MoveOnly.h" #include "test_allocator.h" +#include "test_macros.h" struct DefaultCtableComp { explicit DefaultCtableComp() { default_constructed_ = true; } @@ -29,7 +30,12 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +void test() { { std::flat_set m; assert(m.empty()); @@ -60,6 +66,32 @@ int main(int, char**) { assert(m.key_comp().default_constructed_); } } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp deleted file mode 100644 index b4a3b6de205a31..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set() -// noexcept( -// is_nothrow_default_constructible_v && -// is_nothrow_default_constructible_v); - -// This tests a conforming extension - -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -struct ThrowingCtorComp { - ThrowingCtorComp() noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -int main(int, char**) { -#if defined(_LIBCPP_VERSION) - { - using C = std::flat_set; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set, std::vector>>; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } -#endif // _LIBCPP_VERSION - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp index c0d315c0ce74b4..fa1e2478af4599 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -27,7 +27,7 @@ struct ThrowingDtorComp { ~ThrowingDtorComp() noexcept(false) {} }; -int main(int, char**) { +void test() { { using C = std::flat_set; static_assert(std::is_nothrow_destructible_v); @@ -52,6 +52,10 @@ int main(int, char**) { C c; } #endif // _LIBCPP_VERSION +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp index cd2319e91f760d..9aed5c88ee7268 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -35,7 +35,7 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -146,6 +146,10 @@ int main(int, char**) { M m({5, 2, 2, 3, 1, 3}, {}, a); assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp index 65eebc21a66c4c..2d0b07c9155fdb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -29,7 +29,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -131,6 +131,10 @@ int main(int, char**) { LIBCPP_ASSERT(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp index 69b340ad09fe15..b2853844b986c6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -25,7 +25,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; using A = test_allocator; @@ -79,5 +79,110 @@ int main(int, char**) { LIBCPP_ASSERT(m1.empty()); LIBCPP_ASSERT(m1.size() == 0); } +} + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +void test_move_noexcept() { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +} + +#if !defined(TEST_HAS_NO_EXCEPTIONS) +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +void test_move_exception() { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } +} +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + +int main(int, char**) { + test(); + test_move_noexcept(); +#if !defined(TEST_HAS_NO_EXCEPTIONS) + test_move_exception(); +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp index fc7f68d8c967ad..489b6ff36324b3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -53,7 +53,7 @@ int main(int, char**) { assert(m.size() == 3); auto keys = std::move(m).extract(); assert(keys.get_allocator() == A(3)); - assert(std::ranges::equal(keys, expected )); + assert(std::ranges::equal(keys, expected)); // The original flat_set is moved-from. assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); @@ -63,13 +63,17 @@ int main(int, char**) { } { // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, CopyOnlyVector>; + using M = std::flat_set, CopyOnlyVector>; M m1 = M({1, 2, 3}); M m2(std::move(m1), std::allocator{}); assert(m2.size() == 3); check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index b16dc38dd40285..e55a0516ed1bed 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -22,11 +22,144 @@ #include "test_macros.h" #include "MoveOnly.h" +#include "../helpers.h" #include "../../../test_compare.h" #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +void test_move_assign_clears() { + // Preserves the class invariant for the moved-from flat_set. + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } +} + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +void test_move_assign_no_except() { + // This tests a conforming extension + + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } +} + +void test() { { using C = test_less; using A1 = test_allocator; @@ -64,6 +197,12 @@ int main(int, char**) { assert(ks.get_allocator() == A()); assert(mo.empty()); } +} + +int main(int, char**) { + test(); + test_move_assign_clears(); + test_move_assign_no_except(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp deleted file mode 100644 index 50817f4be8a812..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&&); -// Preserves the class invariant for the moved-from flat_set. - -#include -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -struct MoveNegates { - int value_ = 0; - MoveNegates() = default; - MoveNegates(int v) : value_(v) {} - MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } - MoveNegates& operator=(MoveNegates&& rhs) { - value_ = rhs.value_; - rhs.value_ = -rhs.value_; - return *this; - } - ~MoveNegates() = default; - auto operator<=>(const MoveNegates&) const = default; -}; - -struct MoveClears { - int value_ = 0; - MoveClears() = default; - MoveClears(int v) : value_(v) {} - MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } - MoveClears& operator=(MoveClears&& rhs) { - value_ = rhs.value_; - rhs.value_ = 0; - return *this; - } - ~MoveClears() = default; - auto operator<=>(const MoveClears&) const = default; -}; - -int main(int, char**) { - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, std::vector>; - M m1 = M({1, 2, 3}); - M m2 = M({1, 2}); - m2 = std::move(m1); - assert(m2.size() == 3); - check_invariant(m1); - LIBCPP_ASSERT(m1.empty()); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp deleted file mode 100644 index 86f3568f0d67a6..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&& c) -// noexcept( -// is_nothrow_move_assignable::value && -// is_nothrow_move_assignable::value && -// is_nothrow_copy_assignable::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include - -#include "MoveOnly.h" -#include "test_allocator.h" -#include "test_macros.h" - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -struct MoveThrowsComp { - MoveThrowsComp(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp(const MoveThrowsComp&) noexcept(true); - MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); - bool operator()(const auto&, const auto&) const; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - // Test with a comparator that throws on move-assignment. - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); - } - { - // Test with a container that throws on move-assignment. - using C = std::flat_set, std::pmr::vector>; - static_assert(!std::is_nothrow_move_assignable_v); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp deleted file mode 100644 index 17e4e40387606c..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 -// UNSUPPORTED: no-exceptions - -// - -// flat_set(flat_set&& s); -// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. - -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -static int countdown = 0; - -struct EvilContainer : std::vector { - EvilContainer() = default; - EvilContainer(EvilContainer&& rhs) { - // Throw on move-construction. - if (--countdown == 0) { - rhs.insert(rhs.end(), 0); - rhs.insert(rhs.end(), 0); - throw 42; - } - } -}; - -int main(int, char**) { - { - using M = std::flat_set, EvilContainer>; - M mo = {1, 2, 3}; - countdown = 1; - try { - M m = std::move(mo); - assert(false); // not reached - } catch (int x) { - assert(x == 42); - } - // The source flat_set maintains its class invariant. - check_invariant(mo); - LIBCPP_ASSERT(mo.empty()); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp deleted file mode 100644 index 49d1151fd8a993..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set(flat_set&&) -// noexcept(is_nothrow_move_constructible::value && -// is_nothrow_move_constructible::value && -// is_nothrow_copy_constructible::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -template -struct ThrowingMoveAllocator { - using value_type = T; - explicit ThrowingMoveAllocator() = default; - ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; - ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} - T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } - void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } - friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; -}; - -struct ThrowingMoveComp { - ThrowingMoveComp() = default; - ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} - ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - { - using C = std::flat_set, std::deque>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#if _LIBCPP_VERSION - { - // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators - using C = std::flat_set, std::deque>>; - static_assert(!std::is_nothrow_move_constructible_v>>); - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#endif // _LIBCPP_VERSION - { - // Comparator fails to be nothrow-move-constructible - using C = std::flat_set; - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp index 785718d2eed333..1a4eafa8802918 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -28,7 +28,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // flat_set(const Allocator& a); using M = std::flat_set, std::pmr::vector>; @@ -317,6 +317,10 @@ int main(int, char**) { assert(vm[0].key_comp() == C(4)); assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp index bb9f99c228bfec..bd7b5c12432e96 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -56,7 +56,7 @@ static_assert( !std:: is_constructible_v>, std::less, std::allocator>); -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -168,6 +168,10 @@ int main(int, char**) { assert(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp index 2d442d49667bd0..873ff32b62936a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -138,6 +138,10 @@ int main(int, char**) { assert(m2 == m); assert(std::move(m2).extract().get_allocator() == A(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp index 01956a78c7f48d..a8dac35aefee81 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -33,10 +33,10 @@ template std::initializer_list il = {1, 2, 4, 5}; -const auto il1 = il; -const auto il2 = il; +void test() { + const auto il1 = il; + const auto il2 = il; -int main(int, char**) { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -145,6 +145,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp index b5229a84dd5133..b184ee9c3f5aba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -28,7 +28,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -151,6 +151,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp index 134db83aef3cad..806779bc7d16bc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -49,7 +49,7 @@ void test0( } template -void test() { +void test_one() { // Test all the plausible signatures for this predicate. auto is1 = [](typename S::const_reference v) { return v == 1; }; auto is2 = [](typename S::value_type v) { return v == 2; }; @@ -76,14 +76,18 @@ void test() { test0({1, 2, 3}, False, {1, 2, 3}, 0); } +void test() { + test_one>(); + test_one, std::vector>>>(); + test_one, std::vector>>>(); + test_one, std::deque>>>(); + test_one, std::deque>>>(); + test_one>(); + test_one>(); +} + int main(int, char**) { - test>(); - test, std::vector>>>(); - test, std::vector>>>(); - test, std::deque>>>(); - test, std::deque>>>(); - test>(); - test>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp index 6bbe1ad4f01670..37b4a40f0165cf 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -65,7 +65,7 @@ struct ErasurePredicate { bool operator()(const auto& x) const { return (3 <= x && x <= 5); } }; -int main(int, char**) { +void test() { const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; { using M = std::flat_set; @@ -124,5 +124,10 @@ int main(int, char**) { } } } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp index c07297a141ad10..846bcff63d7736 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -30,7 +30,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -67,15 +67,15 @@ void test() { assert(i == m.begin()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::iterator ii1{}, ii2{}; C::iterator ii4 = ii1; C::const_iterator cii{}; @@ -88,6 +88,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp index 29441dcc57d40e..3027cdd4076eea 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using KI = typename KeyContainer::iterator; @@ -144,11 +144,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp index a16383cdcf5383..d1e4cef3de19e8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include -int main(int, char**) { +void test() { { using M = std::flat_set, std::deque>; M m = {1, 2, 3, 4}; @@ -69,7 +69,7 @@ int main(int, char**) { } { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::reverse_iterator ii1{}, ii2{}; C::reverse_iterator ii4 = ii1; C::const_reverse_iterator cii{}; @@ -82,6 +82,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp index 221a13fa057577..efa13a51c30bb3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -38,7 +38,7 @@ static_assert(NoExceptClear, ThrowOnMoveContai #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -50,13 +50,17 @@ void test() { assert(m.size() == 0); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp index 95f7a3c5f5d34a..79800e894afbfc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -28,7 +28,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -121,21 +121,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp index de855d5e5c3009..b3bd8adf0c35d8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -27,7 +27,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = M::iterator; @@ -134,21 +134,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp index 386af04d26e9a2..42562b84b4e22d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -27,7 +27,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -106,16 +106,21 @@ void test() { assert(i8 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp index 7416977844e5df..d402a7ba0285ec 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -77,15 +77,21 @@ void test() { assert(i4 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp index 25d4f4af19608b..d81422d3871876 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template > -void test() { +void test_one() { using M = std::flat_set; auto make = [](std::initializer_list il) { @@ -70,22 +70,27 @@ void test() { assert(m.empty()); } -int main(int, char**) { - test>(); - test, std::greater<>>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one, std::greater<>>(); + test_one>(); + test_one>(); + test_one>>(); +} - { - auto erase_function = [](auto& m, auto key_arg) { - using Map = std::decay_t; - using Key = typename Map::key_type; - const Key key{key_arg}; - m.erase(key); - }; - test_erase_exception_guarantee(erase_function); - } +void test_exception() { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp index cbf7cac603806d..c383844eb4973e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -50,7 +50,7 @@ struct HeterogeneousKey { }; template -void test_simple() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -86,11 +86,11 @@ void test_transparent_comparator() { assert(m == expected); } -int main(int, char**) { - test_simple>(); - test_simple>(); - test_simple>(); - test_simple>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_transparent_comparator>(); test_transparent_comparator>(); @@ -129,14 +129,20 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } - { - auto erase_transparent = [](auto& m, auto key_arg) { - using Set = std::decay_t; - using Key = typename Set::key_type; - m.erase(Transparent{key_arg}); - }; - test_erase_exception_guarantee(erase_transparent); - } +} + +void test_exception() { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp index c3bbffabb90a08..dfa21a807f0254 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -33,7 +33,7 @@ static_assert(!CanExtract const&>); static_assert(!CanExtract const&&>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; M m = M({1, 2, 3}); @@ -45,11 +45,12 @@ void test() { LIBCPP_ASSERT(m.empty()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { // extracted object maintains invariant if the underlying container does not clear after move using M = std::flat_set, CopyOnlyVector>; @@ -59,7 +60,9 @@ int main(int, char**) { check_invariant(m); LIBCPP_ASSERT(m.empty()); } +} +void test_exception() { { #ifndef TEST_HAS_NO_EXCEPTIONS using KeyContainer = ThrowOnMoveContainer; @@ -79,5 +82,11 @@ int main(int, char**) { } #endif } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp index c0ddadc3006987..e0cb80f74462cd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -59,20 +59,25 @@ void test() { assert(*r.first == 3); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using value_type = typename std::decay_t::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(p); - }; - test_emplace_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp index 7381514a70eabb..bf94fd9f5b11fd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -23,12 +23,12 @@ #include "min_allocator.h" template -void test() { - using Key = typename KeyContainer::value_type; - using M = std::flat_set, KeyContainer>; - using V = typename M::value_type; +void test_one() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; - M m = {1,1,1,3,3,3}; + M m = {1, 1, 1, 3, 3, 3}; m.insert({ 4, 4, @@ -48,20 +48,26 @@ void test() { assert(*std::next(m.begin(), 3) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(il); - }; - test_insert_range_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index c343d53a62215a..d6791853e0debd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = typename M::iterator; @@ -55,13 +55,15 @@ void test() { assert(*r == 3); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; using value_type = typename FlatSet::value_type; @@ -69,6 +71,11 @@ int main(int, char**) { m.insert(m.begin(), p); }; test_emplace_exception_guarantee(insert_func); - } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp index d20a8ef8fdd92d..8063686c960ed3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; int ar1[] = { @@ -73,15 +73,22 @@ void test() { M expected2{0, 1, 2, 3, 4}; assert(m == expected2); } + +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp index 84b6c7fc1d34f6..d29de98e4d3ddb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -22,7 +22,7 @@ #include "test_macros.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -49,25 +49,30 @@ void test() { assert(*r == V(3)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(m.begin(), std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp index 536307252c6405..ed33827a7355c9 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -39,7 +39,7 @@ static_assert(!CanInsertRange*>>) static_assert(!CanInsertRange*>>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -75,31 +75,29 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { - // Items are forwarded correctly from the input range (P2767). + // Items are forwarded correctly from the input range. MoveOnly a[] = {3, 1, 4, 1, 5}; std::flat_set m; m.insert_range(a | std::views::as_rvalue); MoveOnly expected[] = {1, 3, 4, 5}; assert(std::ranges::equal(m, expected)); } - { - // The element type of the range doesn't need to be std::pair (P2767). - int pa[] = {3, 1, 4, 1, 5}; - std::deque> a(pa, pa + 5); - std::flat_set m; - m.insert_range(a); - int expected[] = {1, 3, 4, 5}; - assert(std::ranges::equal(m, expected)); - } - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; - test_insert_range_exception_guarantee(insert_func); - } +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp index 7d95f0521eb1f6..faf74142caff5c 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -25,7 +25,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; using R = std::pair; @@ -57,24 +57,30 @@ void test() { assert(*r.first == V(3)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp index fa5bf86830daec..38c36d1befaa7c 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -38,21 +38,26 @@ void test() { assert(*std::next(m.begin(), 4) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(std::sorted_unique, il); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp index ef7b8391cee33c..6258c4dbfdcbba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -60,18 +60,23 @@ void test() { assert(m == expected2); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - m.insert(std::sorted_unique, newValues.begin(), newValues.end()); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp index 72d7261a182547..d2ddf95aac2bb7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -57,7 +57,7 @@ struct CompareCounter { }; template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -121,11 +121,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // no ambiguity between insert(pos, P&&) and insert(first, last) @@ -139,6 +139,9 @@ int main(int, char**) { ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); } +} + +void test_exception() { { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; @@ -165,5 +168,11 @@ int main(int, char**) { }; test_emplace_exception_guarantee(insert_func_iter); } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp index 49cb6eb6163c90..fca33bd41449e0 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -31,7 +31,7 @@ static_assert(CanReplace>); static_assert(!CanReplace&>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -43,30 +43,36 @@ void test() { assert(std::ranges::equal(m, expected_keys)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { #ifndef TEST_HAS_NO_EXCEPTIONS - using KeyContainer = ThrowOnMoveContainer; - using M = std::flat_set; + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; - M m; - m.emplace(1); - m.emplace(2); - try { - KeyContainer new_keys{3, 4}; - m.replace(std::move(new_keys)); - assert(false); - } catch (int) { - check_invariant(m); - // In libc++, we clear the map - LIBCPP_ASSERT(m.size() == 0); - } -#endif + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); } +#endif +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp index bc7baa67e52a59..ed13ba1ef3fea7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -24,6 +24,8 @@ #include "test_macros.h" #include "../helpers.h" +#include "check_assertion.h" + // test noexcept template @@ -38,7 +40,7 @@ static_assert(NoExceptAdlSwap, ThrowOnMoveCont #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -84,11 +86,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp index b0b06a9499efc7..1eac55d768ce0b 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -37,7 +37,7 @@ static_assert(NoExceptMemberSwap, ThrowOnMoveC #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -82,11 +82,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp index 971b5e1c338dd1..ba2c428c9e30e2 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -21,7 +21,7 @@ #include "test_macros.h" -int main(int, char**) { +void test() { { using M = std::flat_set; using Comp = std::less; // the default @@ -67,6 +67,10 @@ int main(int, char**) { assert(vc(1, 2)); assert(!vc(2, 1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp index b14da66f611301..e23683f6f28945 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp index 507560608952b0..0cdff44d11274f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanContains); static_assert(!CanContains); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.contains(Transparent{"g"}) == false); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,5 +66,10 @@ int main(int, char**) { assert(b); assert(transparent_used); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp index 478f615358b606..017f0fed3e9816 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using S = typename KeyContainer::size_type; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp index b591258f74399c..0c5ce9d5799651 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanCount); static_assert(!CanCount); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.count(Transparent{"g"}) == 0); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,6 +66,10 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp index a088b7fee17d2c..b55cbe2ac42a00 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -67,11 +67,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp index ede5d91e19b9fd..97c4af19eaef37 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanEqualRange); static_assert(!CanEqualRange); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -77,11 +77,11 @@ void test() { test_not_found(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -92,6 +92,10 @@ int main(int, char**) { assert(p.first != p.second); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp index cf0dd2d1dd831c..9ee8f043e1d9cd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -25,7 +25,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m = {1, 2, 4, 5, 8}; @@ -43,11 +43,15 @@ void test() { assert(std::as_const(m).find(9) == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp index 730a57b0a6cb85..cc8ea12bcf4a6a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanFind); static_assert(!CanFind); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -68,11 +68,11 @@ void test() { test_find(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -83,6 +83,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp index 093c32e537ed35..1ceddb2f1c9d26 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -60,11 +60,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp index 18f9bc6dd32955..19991ca05fbc8a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanLowerBound); static_assert(!CanLowerBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,11 @@ void test() { test_lower_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -89,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp index ab34de85103175..f25896e1229397 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -61,11 +61,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp index 69ce2ae926a305..c9b519d2032193 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanUpperBound); static_assert(!CanUpperBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,12 @@ void test() { test_upper_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { bool transparent_used = false; TransparentComparator c(transparent_used); @@ -88,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h index 9fff262d84234e..2ee8b021337a06 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SUPPORT_flat_set_HELPERS_H -#define SUPPORT_flat_set_HELPERS_H +#ifndef SUPPORT_FLAT_SET_HELPERS_H +#define SUPPORT_FLAT_SET_HELPERS_H #include #include @@ -149,6 +149,19 @@ struct EmplaceUnsafeContainer : std::vector { throw 42; } + + template + auto insert_range(Args&&... args) + -> decltype(std::declval>().insert_range(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } }; template @@ -291,4 +304,4 @@ class Moveable { bool moved() const { return int_ == -1; } }; -#endif // SUPPORT_flat_set_HELPERS_H +#endif // SUPPORT_FLAT_SET_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp index c4a9810016536b..faf746861df309 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -27,7 +27,10 @@ struct A { // Implement the operator< required in order to instantiate flat_set bool operator<(A const& L, A const& R) { return L.data < R.data; } +void test() { A a; } + int main(int, char**) { - A a; + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp index f6d08bb736d300..3e7aecee77fdd8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -31,7 +31,7 @@ #include "test_container_comparisons.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -69,11 +69,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { using C = std::flat_set; @@ -101,5 +101,10 @@ int main(int, char**) { assert(s1 != s2); assert((s1 <=> s2) == std::partial_ordering::unordered); } +} + +int main(int, char**) { + test(); + return 0; } >From 6fa4b5763cccee5d1631d9239c12f33d5c656956 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 14:08:01 +0000 Subject: [PATCH 3/8] review --- .../flat.set/assert.sorted_unique.pass.cpp | 226 ++++++++++++++++++ .../assign_initializer_list.pass.cpp | 6 +- .../flat.set.cons/move_assign.pass.cpp | 67 ++++-- 3 files changed, 280 insertions(+), 19 deletions(-) create mode 100644 libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp diff --git a/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp new file mode 100644 index 00000000000000..62903af7f4e477 --- /dev/null +++ b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp @@ -0,0 +1,226 @@ +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: libcpp-hardening-mode=none +// REQUIRES: libcpp-hardening-mode=debug +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// + +// flat_set(container_type , const key_compare& __comp = key_compare()) +// flat_set(const container_type& , const _Allocator& ) +// flat_set(const container_type& , const key_compare&, const _Allocator& ) +// void replace(container_type&& ) +// + +#include +#include +#include +#include +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + using M = std::flat_set; + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{1, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{2, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7e948d7c5fe976..ad49b621490366 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -30,14 +30,16 @@ void test_one() { { M m = {8, 10}; assert(m.size() == 2); - m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + std::same_as decltype(auto) r = m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + assert(&r == &m); int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); } { M m = {10, 8}; assert(m.size() == 2); - m = {3}; + std::same_as decltype(auto) r = m = {3}; + assert(&r == &m); int expected[] = {3}; assert(std::ranges::equal(m, expected)); } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index e55a0516ed1bed..0e0ab0aa135f9f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -55,6 +55,19 @@ struct MoveClears { auto operator<=>(const MoveClears&) const = default; }; +#if !defined(TEST_HAS_NO_EXCEPTIONS) +struct MoveAssignThrows : std::vector { + using std::vector::vector; + MoveAssignThrows& operator=(MoveAssignThrows&& other) { + push_back(0); + push_back(0); + other.push_back(0); + other.push_back(0); + throw 42; + } +}; +#endif // TEST_HAS_NO_EXCEPTIONS + void test_move_assign_clears() { // Preserves the class invariant for the moved-from flat_set. { @@ -101,6 +114,23 @@ void test_move_assign_clears() { check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +#if !defined(TEST_HAS_NO_EXCEPTIONS) + { + using M = std::flat_set, MoveAssignThrows>; + M m1 = {1, 2, 3}; + M m2 = {1, 2}; + try { + m2 = std::move(m1); + assert(false); + } catch (int e) { + assert(e == 42); + } + check_invariant(m1); + check_invariant(m2); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m2.empty()); + } +#endif // TEST_HAS_NO_EXCEPTIONS } struct MoveSensitiveComp { @@ -161,12 +191,13 @@ void test_move_assign_no_except() { void test() { { - using C = test_less; - using A1 = test_allocator; - using M = std::flat_set>; - M mo = M({1, 2, 3}, C(5), A1(7)); - M m = M({}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{1, 2, 3})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -174,12 +205,13 @@ void test() { assert(mo.empty()); } { - using C = test_less; - using A1 = other_allocator; - using M = std::flat_set>; - M mo = M({4, 5}, C(5), A1(7)); - M m = M({1, 2, 3, 4}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{4, 5})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -187,11 +219,12 @@ void test() { assert(mo.empty()); } { - using A = min_allocator; - using M = std::flat_set, std::vector>; - M mo = M({5, 4, 3}, A()); - M m = M({4, 3, 2, 1}, A()); - m = std::move(mo); + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{5, 4, 3})); auto ks = std::move(m).extract(); assert(ks.get_allocator() == A()); >From c65a37ea8012b92dc5575be91a1a18851a8caeaa Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 16:23:56 +0000 Subject: [PATCH 4/8] clang-format --- .../flat.set/flat.set.capacity/max_size.pass.cpp | 1 - .../flat.set.modifiers/insert_iter_cv.pass.cpp | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index 0489d886257911..dde1f7092e5b18 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -25,7 +25,6 @@ #include "test_macros.h" void test() { - { using A1 = limited_allocator; using C = std::flat_set, std::vector>; diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index d6791853e0debd..76b4d5f0eb7cc6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -56,7 +56,6 @@ void test_one() { } void test() { - test_one>(); test_one>(); test_one>(); @@ -64,13 +63,13 @@ void test() { } void test_exception() { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(m.begin(), p); - }; - test_emplace_exception_guarantee(insert_func); + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); } int main(int, char**) { >From 61147247cfcf3fd4623587bddaa07a2c4783d2b6 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 16:59:41 +0000 Subject: [PATCH 5/8] CI --- libcxx/docs/ReleaseNotes/21.rst | 1 + libcxx/docs/Status/Cxx23Papers.csv | 2 +- libcxx/modules/std.compat.cppm.in | 3 - libcxx/modules/std.cppm.in | 4 +- libcxx/modules/std/flat_set.inc | 4 +- .../test/libcxx/transitive_includes/cxx03.csv | 8 ++ .../test/libcxx/transitive_includes/cxx11.csv | 8 ++ .../test/libcxx/transitive_includes/cxx14.csv | 8 ++ .../test/libcxx/transitive_includes/cxx17.csv | 8 ++ .../test/libcxx/transitive_includes/cxx20.csv | 8 ++ .../test/libcxx/transitive_includes/cxx23.csv | 15 +++- .../test/libcxx/transitive_includes/cxx26.csv | 14 ++++ .../flat_set.version.compile.pass.cpp | 80 +++++++++++++++++++ libcxx/utils/libcxx/header_information.py | 2 +- 14 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad3942..0c1029f50a6fe7 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -39,6 +39,7 @@ Implemented Papers ------------------ - N4258: Cleaning-up noexcept in the Library (`Github `__) +- P1222R4: A Standard ``flat_set`` is partially implemented and ``flat_set`` is provided (`Github `__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 264c5417a5c28b..bcd9c5c43a9c69 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -54,7 +54,7 @@ "`P0009R18 `__","mdspan: A Non-Owning Multidimensional Array Reference","2022-07 (Virtual)","|Complete|","18","" "`P0429R9 `__","A Standard ``flat_map``","2022-07 (Virtual)","|Complete|","20","" "`P1169R4 `__","``static operator()``","2022-07 (Virtual)","|Complete|","16","" -"`P1222R4 `__","A Standard ``flat_set``","2022-07 (Virtual)","","","" +"`P1222R4 `__","A Standard ``flat_set``","2022-07 (Virtual)","|In progress|","","" "`P1223R5 `__","``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()``","2022-07 (Virtual)","|Complete|","19","" "`P1467R9 `__","Extended ``floating-point`` types and standard names","2022-07 (Virtual)","","","" "`P1642R11 `__","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","2022-07 (Virtual)","","","" diff --git a/libcxx/modules/std.compat.cppm.in b/libcxx/modules/std.compat.cppm.in index 5cea1b75bfc170..95931447ccdc64 100644 --- a/libcxx/modules/std.compat.cppm.in +++ b/libcxx/modules/std.compat.cppm.in @@ -53,9 +53,6 @@ module; # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in index b9d00df70658d8..5c523691bff4e2 100644 --- a/libcxx/modules/std.cppm.in +++ b/libcxx/modules/std.cppm.in @@ -65,6 +65,7 @@ module; #include #include #include +#include #include #include #if _LIBCPP_HAS_LOCALIZATION @@ -162,9 +163,6 @@ module; # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std/flat_set.inc b/libcxx/modules/std/flat_set.inc index a86cc1eae02a62..3f2c6e09a0ebe4 100644 --- a/libcxx/modules/std/flat_set.inc +++ b/libcxx/modules/std/flat_set.inc @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// export namespace std { -#if 0 +#if _LIBCPP_STD_VER >= 23 // [flat.set], class template flat_­set using std::flat_set; @@ -19,7 +19,9 @@ export namespace std { // [flat.set.erasure], erasure for flat_­set using std::erase_if; +#endif // _LIBCPP_STD_VER >= 23 +#if 0 // [flat.multiset], class template flat_­multiset using std::flat_multiset; diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv index ec5db90597d927..c0031543e47bce 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -683,6 +683,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv index ec5db90597d927..c0031543e47bce 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -683,6 +683,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv index 95024df0590b84..c2eb5b44e8d7a7 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -701,6 +701,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv index a3518f7f62ecb9..332cb62f35b5f4 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -709,6 +709,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv index 6de95139279471..55c79acff5a8f9 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -705,6 +705,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv index 17972b84537436..7da07a8b3749b2 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -345,6 +345,20 @@ flat_map optional flat_map stdexcept flat_map tuple flat_map version +flat_set cctype +flat_set climits +flat_set compare +flat_set cstdint +flat_set cstring +flat_set cwchar +flat_set cwctype +flat_set initializer_list +flat_set limits +flat_set optional +flat_set stdexcept +flat_set tuple +flat_set type_traits +flat_set version format array format cctype format cerrno @@ -556,7 +570,6 @@ istream ios istream iosfwd istream limits istream locale - istream ratio istream stdexcept istream streambuf diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv index 00ab78e61a4576..4c2782a4ce5cf9 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -345,6 +345,20 @@ flat_map optional flat_map stdexcept flat_map tuple flat_map version +flat_set cctype +flat_set climits +flat_set compare +flat_set cstdint +flat_set cstring +flat_set cwchar +flat_set cwctype +flat_set initializer_list +flat_set limits +flat_set optional +flat_set stdexcept +flat_set tuple +flat_set type_traits +flat_set version format array format cctype format cerrno diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp new file mode 100644 index 00000000000000..f9d0b0a6b4e4f6 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. +// +// clang-format off + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_flat_set 202207L [C++23] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should be defined in c++23" +# endif +# if __cpp_lib_flat_set != 202207L +# error "__cpp_lib_flat_set should have the value 202207L in c++23" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#elif TEST_STD_VER > 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should be defined in c++26" +# endif +# if __cpp_lib_flat_set != 202207L +# error "__cpp_lib_flat_set should have the value 202207L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#endif // TEST_STD_VER > 23 + diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py index 9a723b61524cd5..9811b42d510ca3 100644 --- a/libcxx/utils/libcxx/header_information.py +++ b/libcxx/utils/libcxx/header_information.py @@ -164,7 +164,6 @@ def __hash__(self) -> int: # modules will fail to build if a header is added but this list is not updated. headers_not_available = list(map(Header, [ "debugging", - "flat_set", "generator", "hazard_pointer", "inplace_vector", @@ -261,6 +260,7 @@ def __hash__(self) -> int: "deque": ["compare", "initializer_list"], "filesystem": ["compare"], "flat_map": ["compare", "initializer_list"], + "flat_set": ["compare", "initializer_list"], "forward_list": ["compare", "initializer_list"], "ios": ["iosfwd"], "iostream": ["ios", "istream", "ostream", "streambuf"], >From a7583dad7798ec3f4259a2bcd4e851a85c7e04d6 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 18:05:17 +0000 Subject: [PATCH 6/8] deduction --- .../flat.set.cons/deduct.compile.pass.cpp | 14 +- .../flat.set/flat.set.cons/deduct.pass.cpp | 239 +++++++++--------- 2 files changed, 121 insertions(+), 132 deletions(-) diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp index 5db8c4ca722466..1161fe6e61c78e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp @@ -23,27 +23,21 @@ struct NotAnAllocator { }; template -concept CanDeductFlatSet = requires { std::flat_set{std::declval()...}; }; +concept CanDeductFlatSet = requires { std::flat_set(std::declval()...); }; -static_assert(CanDeductFlatSet, std::vector>); +static_assert(CanDeductFlatSet>); // cannot deduce Key and T from nothing static_assert(!CanDeductFlatSet<>); -// cannot deduce Key and T from just (KeyContainer), even if it's a container of pairs -static_assert(!CanDeductFlatSet>>); - -// cannot deduce Key and T from just (KeyContainer, Allocator) -static_assert(!CanDeductFlatSet, std::allocator>>); - // cannot deduce Key and T from just (Compare) static_assert(!CanDeductFlatSet>); // cannot deduce Key and T from just (Compare, Allocator) -static_assert(!CanDeductFlatSet, std::allocator>); +static_assert(!CanDeductFlatSet, std::allocator>); // cannot deduce Key and T from just (Allocator) -static_assert(!CanDeductFlatSet>); +static_assert(!CanDeductFlatSet>); // cannot convert from some arbitrary unrelated type static_assert(!CanDeductFlatSet); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp index 607fe0d1a9713a..491c77d3737af1 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -116,8 +116,8 @@ void test_containers_compare() { } void test_iter_iter() { - const int arr[] = {1, 2, 1, INT_MAX, 3}; - const int sorted_arr[] = {1, 2, 3, INT_MAX}; + int arr[] = {1, 2, 1, INT_MAX, 3}; + int sorted_arr[] = {1, 2, 3, INT_MAX}; const int arrc[] = {1, 2, 1, INT_MAX, 3}; const int sorted_arrc[] = {1, 2, 3, INT_MAX}; { @@ -154,6 +154,12 @@ void test_iter_iter() { std::flat_set m(mo.cbegin(), mo.cend()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } + { + int source[3] = {1, 2, 3}; + std::flat_set s(source, source + 3); + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } { // This does not deduce to flat_set(InputIterator, InputIterator) // But deduces to flat_set(initializer_list) @@ -171,140 +177,125 @@ void test_iter_iter() { } void test_iter_iter_compare() { - // const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - // const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // using C = std::greater; - // { - // std::flat_set m(std::begin(arr), std::end(arr), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::begin(arrc), std::end(arrc), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set mo; - // std::flat_set m(mo.begin(), mo.end(), C()); - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // } - // { - // std::flat_set mo; - // std::flat_set m(mo.cbegin(), mo.cend(), C()); - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // } + int arr[] = {1, 2, 1, INT_MAX, 3}; + int sorted_arr[] = {INT_MAX, 3, 2, 1}; + const int arrc[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arrc[] = {INT_MAX, 3, 2, 1}; + using C = std::greater; + { + std::flat_set m(std::begin(arr), std::end(arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } } void test_initializer_list() { - // const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - // { - // std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) - // ASSERT_SAME_TYPE(decltype(s), std::flat_set); - // assert(s.size() == 1); - // } - // { - // using M = std::flat_set; - // M m; - // std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) - // ASSERT_SAME_TYPE(decltype(s), std::flat_set); - // assert(s.size() == 1); - // assert(s[m] == m); - // } + const int sorted_arr[] = {1, 2, 3, INT_MAX}; + { + std::flat_set m{1, 2, 1, INT_MAX, 3}; + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {1, 2, 3, INT_MAX}); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set s = {1}; + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } + { + using M = std::flat_set; + M m; + std::flat_set s{m, m}; // flat_set(initializer_list) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } } void test_initializer_list_compare() { - // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // using C = std::greater; - // { - // std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } + const int sorted_arr[] = {INT_MAX, 3, 2, 1}; + using C = std::greater; + { + std::flat_set m({1, 2, 1, INT_MAX, 3}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {INT_MAX, 3, 2, 1}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } } void test_from_range() { - // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - // const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; - // { - // std::flat_set s(std::from_range, r); - // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - // assert(std::ranges::equal(s, expected)); - // } - // { - // std::flat_set s(std::from_range, r, test_allocator(0, 42)); - // ASSERT_SAME_TYPE( - // decltype(s), - // std::flat_set, - // std::vector>, - // std::vector>>); - // assert(std::ranges::equal(s, expected)); - // assert(s.keys().get_allocator().get_id() == 42); - // assert(s.values().get_allocator().get_id() == 42); - // } + std::list r = {1, 2, 1, INT_MAX, 3}; + const int expected[] = {1, 2, 3, INT_MAX}; + { + std::flat_set s(std::from_range, r); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, test_allocator(0, 42)); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(std::move(s).extract().get_allocator().get_id() == 42); + } } void test_from_range_compare() { - // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - // const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; - // { - // std::flat_set s(std::from_range, r, std::greater()); - // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - // assert(std::ranges::equal(s, expected)); - // } - // { - // std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); - // ASSERT_SAME_TYPE( - // decltype(s), - // std::flat_set, - // std::vector>, - // std::vector>>); - // assert(std::ranges::equal(s, expected)); - // assert(s.keys().get_allocator().get_id() == 42); - // assert(s.values().get_allocator().get_id() == 42); - // } + std::list r = {1, 2, 1, INT_MAX, 3}; + const int expected[] = {INT_MAX, 3, 2, 1}; + { + std::flat_set s(std::from_range, r, std::greater()); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(std::move(s).extract().get_allocator().get_id() == 42); + } } -int main(int, char**) { +void test() { // Each test function also tests the sorted_unique-prefixed and allocator-suffixed overloads. test_copy(); test_containers(); @@ -317,6 +308,10 @@ int main(int, char**) { test_from_range_compare(); AssociativeContainerDeductionGuidesSfinaeAway>(); +} + +int main(int, char**) { + test(); return 0; } >From 8e266130512ef5788ea87361fcd0b194b0ae850e Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 18:45:39 +0000 Subject: [PATCH 7/8] CI --- libcxx/include/__flat_set/flat_set.h | 4 ++-- libcxx/include/module.modulemap | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index 37e4c9f7c686b0..30fe1343e63ee9 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -838,8 +838,8 @@ template _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); - auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { - return static_cast(__pred(e)); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& __e) -> bool { + return static_cast(__pred(__e)); }); auto __res = __flat_set.__keys_.end() - __it; __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index abc351d5923963..261362baeec5b8 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1268,6 +1268,7 @@ module std [system] { header "__flat_set/flat_set.h" export std.vector.vector export std.vector.fwd + export std.flat_map.sorted_unique } header "flat_set" >From 6476ae0d0059fc4519f0f3b769ef5cfcf9aa53ba Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 19:14:41 +0000 Subject: [PATCH 8/8] CI again --- libcxx/include/module.modulemap | 2 +- .../flat.set/flat.set.cons/default.pass.cpp | 1 - .../flat.set/flat.set.modifiers/insert_transparent.pass.cpp | 6 +++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 261362baeec5b8..3d9e9d42894410 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1268,8 +1268,8 @@ module std [system] { header "__flat_set/flat_set.h" export std.vector.vector export std.vector.fwd - export std.flat_map.sorted_unique } + module sorted_unique { header "__flat_map/sorted_unique.h" } header "flat_set" export * diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp index 292af96c61582f..5cbd557eb8562e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -53,7 +53,6 @@ void test() { } { using A1 = explicit_allocator; - using A2 = explicit_allocator; { std::flat_set> m; assert(m.empty()); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp index d2ddf95aac2bb7..4fe71b1cb898f2 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -146,9 +146,9 @@ void test_exception() { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; struct T { - typename FlatSet::key_type key; - T(typename FlatSet::key_type key) : key(key) {} - operator typename FlatSet::value_type() const { return key; } + typename FlatSet::key_type key_; + T(typename FlatSet::key_type key) : key_(key) {} + operator typename FlatSet::value_type() const { return key_; } }; T t(key_arg); m.insert(t); From libcxx-commits at lists.llvm.org Sun Feb 2 11:57:25 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Sun, 02 Feb 2025 11:57:25 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] implement std::flat_set (PR #125241) In-Reply-To: Message-ID: <679fce25.170a0220.f597b.2778@mx.google.com> https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/125241 >From f315d757119fde3cf298c18914a33e9cf76f27d1 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Fri, 31 Jan 2025 15:53:09 +0000 Subject: [PATCH 1/9] [libc++] implement std::flat_set --- libcxx/include/CMakeLists.txt | 2 + libcxx/include/__flat_set/flat_set.h | 853 ++++++++++++++++++ libcxx/include/flat_set | 59 ++ libcxx/include/module.modulemap | 11 + .../flat.set/flat.set.capacity/empty.pass.cpp | 48 + .../flat.set.capacity/empty.verify.cpp | 20 + .../flat.set.capacity/max_size.pass.cpp | 63 ++ .../flat.set/flat.set.capacity/size.pass.cpp | 66 ++ .../flat.set/flat.set.cons/alloc.pass.cpp | 60 ++ .../assign_initializer_list.pass.cpp | 56 ++ .../flat.set/flat.set.cons/compare.pass.cpp | 83 ++ .../flat.set.cons/containers.pass.cpp | 158 ++++ .../flat.set/flat.set.cons/copy.pass.cpp | 64 ++ .../flat.set.cons/copy_alloc.pass.cpp | 63 ++ .../copy_assign.addressof.compile.pass.cpp | 30 + .../flat.set.cons/copy_assign.pass.cpp | 85 ++ .../flat.set.cons/deduct.compile.pass.cpp | 49 + .../flat.set/flat.set.cons/deduct.pass.cpp | 341 +++++++ .../flat.set.cons/deduct_pmr.pass.cpp | 94 ++ .../flat.set/flat.set.cons/default.pass.cpp | 65 ++ .../flat.set.cons/default_noexcept.pass.cpp | 58 ++ .../flat.set.cons/dtor_noexcept.pass.cpp | 57 ++ .../flat.set.cons/initializer_list.pass.cpp | 151 ++++ .../flat.set/flat.set.cons/iter_iter.pass.cpp | 136 +++ .../flat.set/flat.set.cons/move.pass.cpp | 83 ++ .../flat.set.cons/move_alloc.pass.cpp | 75 ++ .../flat.set.cons/move_assign.pass.cpp | 69 ++ .../flat.set.cons/move_assign_clears.pass.cpp | 101 +++ .../move_assign_noexcept.pass.cpp | 85 ++ .../flat.set.cons/move_exceptions.pass.cpp | 58 ++ .../flat.set.cons/move_noexcept.pass.cpp | 94 ++ .../flat.set/flat.set.cons/pmr.pass.cpp | 322 +++++++ .../flat.set/flat.set.cons/range.pass.cpp | 173 ++++ .../flat.set.cons/sorted_container.pass.cpp | 143 +++ .../sorted_initializer_list.pass.cpp | 150 +++ .../flat.set.cons/sorted_iter_iter.pass.cpp | 156 ++++ .../flat.set.erasure/erase_if.pass.cpp | 89 ++ .../erase_if_exceptions.pass.cpp | 128 +++ .../flat.set.iterators/iterator.pass.cpp | 93 ++ .../iterator_comparison.pass.cpp | 154 ++++ ...rator_concept_conformance.compile.pass.cpp | 77 ++ ...range_concept_conformance.compile.pass.cpp | 52 ++ .../reverse_iterator.pass.cpp | 87 ++ .../flat.set.modifiers/clear.pass.cpp | 62 ++ .../flat.set.modifiers/emplace.pass.cpp | 141 +++ .../flat.set.modifiers/emplace_hint.pass.cpp | 154 ++++ .../flat.set.modifiers/erase_iter.pass.cpp | 121 +++ .../erase_iter_iter.pass.cpp | 91 ++ .../flat.set.modifiers/erase_key.pass.cpp | 91 ++ .../erase_key_transparent.pass.cpp | 142 +++ .../flat.set.modifiers/extract.pass.cpp | 83 ++ .../flat.set.modifiers/insert_cv.pass.cpp | 78 ++ .../insert_initializer_list.pass.cpp | 67 ++ .../insert_iter_cv.pass.cpp | 74 ++ .../insert_iter_iter.pass.cpp | 87 ++ .../insert_iter_rv.pass.cpp | 73 ++ .../flat.set.modifiers/insert_range.pass.cpp | 105 +++ .../flat.set.modifiers/insert_rv.pass.cpp | 80 ++ .../insert_sorted_initializer_list.pass.cpp | 58 ++ .../insert_sorted_iter_iter.pass.cpp | 77 ++ .../insert_transparent.pass.cpp | 169 ++++ .../flat.set.modifiers/replace.pass.cpp | 72 ++ .../swap_exception.pass.cpp | 61 ++ .../flat.set.modifiers/swap_free.pass.cpp | 94 ++ .../flat.set.modifiers/swap_member.pass.cpp | 92 ++ .../flat.set/flat.set.observers/comp.pass.cpp | 72 ++ .../flat.set.operations/contains.pass.cpp | 69 ++ .../contains_transparent.pass.cpp | 70 ++ .../flat.set.operations/count.pass.cpp | 69 ++ .../count_transparent.pass.cpp | 71 ++ .../flat.set.operations/equal_range.pass.cpp | 77 ++ .../equal_range_transparent.pass.cpp | 97 ++ .../flat.set.operations/find.pass.cpp | 53 ++ .../find_transparent.pass.cpp | 88 ++ .../flat.set.operations/lower_bound.pass.cpp | 70 ++ .../lower_bound_transparent.pass.cpp | 94 ++ .../flat.set.operations/upper_bound.pass.cpp | 71 ++ .../upper_bound_transparent.pass.cpp | 93 ++ .../container.adaptors/flat.set/helpers.h | 294 ++++++ .../flat.set/incomplete_type.pass.cpp | 33 + .../flat.set/op_compare.pass.cpp | 105 +++ .../flat.set/types.compile.pass.cpp | 94 ++ 82 files changed, 8453 insertions(+) create mode 100644 libcxx/include/__flat_set/flat_set.h create mode 100644 libcxx/include/flat_set create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/helpers.h create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8dac823503d73f..75acf9f7899ff6 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -367,6 +367,7 @@ set(files __flat_map/sorted_equivalent.h __flat_map/sorted_unique.h __flat_map/utils.h + __flat_set/flat_set.h __format/buffer.h __format/concepts.h __format/container_adaptor.h @@ -986,6 +987,7 @@ set(files fenv.h filesystem flat_map + flat_set float.h format forward_list diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h new file mode 100644 index 00000000000000..c920632c453bf5 --- /dev/null +++ b/libcxx/include/__flat_set/flat_set.h @@ -0,0 +1,853 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FLAT_set_FLAT_SET_H +#define _LIBCPP___FLAT_set_FLAT_SET_H + +#include <__algorithm/lexicographical_compare_three_way.h> +#include <__algorithm/min.h> +#include <__algorithm/ranges_adjacent_find.h> +#include <__algorithm/ranges_equal.h> +#include <__algorithm/ranges_inplace_merge.h> +#include <__algorithm/ranges_lower_bound.h> +#include <__algorithm/ranges_partition_point.h> +#include <__algorithm/ranges_sort.h> +#include <__algorithm/ranges_unique.h> +#include <__algorithm/ranges_upper_bound.h> +#include <__algorithm/remove_if.h> +#include <__assert> +#include <__compare/synth_three_way.h> +#include <__concepts/swappable.h> +#include <__config> +#include <__cstddef/byte.h> +#include <__cstddef/ptrdiff_t.h> +#include <__flat_map/sorted_unique.h> +#include <__functional/invoke.h> +#include <__functional/is_transparent.h> +#include <__functional/operations.h> +#include <__fwd/vector.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/ranges_iterator_traits.h> +#include <__iterator/reverse_iterator.h> +#include <__memory/allocator_traits.h> +#include <__memory/uses_allocator.h> +#include <__memory/uses_allocator_construction.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/container_compatible_range.h> +#include <__ranges/drop_view.h> +#include <__ranges/from_range.h> +#include <__ranges/ref_view.h> +#include <__ranges/size.h> +#include <__ranges/subrange.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/container_traits.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_allocator.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_same.h> +#include <__utility/exception_guard.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include <__utility/scope_guard.h> +#include <__vector/vector.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template , class _KeyContainer = vector<_Key>> +class flat_set { + template + friend class flat_set; + + static_assert(is_same_v<_Key, typename _KeyContainer::value_type>); + static_assert(!is_same_v<_KeyContainer, std::vector>, "vector is not a sequence container"); + +public: + // types + using key_type = _Key; + using value_type = _Key; + using key_compare = __type_identity_t<_Compare>; + using value_compare = _Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename _KeyContainer::size_type; + using difference_type = typename _KeyContainer::difference_type; + using iterator = typename _KeyContainer::const_iterator; + using const_iterator = iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using container_type = _KeyContainer; + +private: + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = + uses_allocator::value; + + _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; + +public: + // [flat.set.cons], construct/copy/destroy + _LIBCPP_HIDE_FROM_ABI + flat_set() noexcept(is_nothrow_default_constructible_v<_KeyContainer> && is_nothrow_default_constructible_v<_Compare>) + : __keys_(), __compare_() {} + + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other) noexcept( + is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : __keys_(std::move(__other.__keys_)), __compare_(std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + // gcc does not like the `throw` keyword in a conditionally noexcept function + if constexpr (!(is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>)) { + throw; + } +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const key_compare& __comp) : __keys_(), __compare_(__comp) {} + + _LIBCPP_HIDE_FROM_ABI explicit flat_set(container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + __sort_and_unique(); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, container_type __keys, const key_compare& __comp = key_compare()) + : __keys_(std::move(__keys)), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(), __compare_(__comp) { + insert(__first, __last); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) + : __keys_(__first, __last), __compare_(__comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg) + : flat_set(from_range, std::forward<_Range>(__rg), key_compare()) {} + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp) : flat_set(__comp) { + insert_range(std::forward<_Range>(__rg)); + } + + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(__il.begin(), __il.end(), __comp) {} + + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp = key_compare()) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + __sort_and_unique(); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates"); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) +# if _LIBCPP_HAS_EXCEPTIONS + try +# endif // _LIBCPP_HAS_EXCEPTIONS + : flat_set(__ctor_uses_allocator_tag{}, __alloc, std::move(__other.__keys_), std::move(__other.__compare_)) { + __other.clear(); +# if _LIBCPP_HAS_EXCEPTIONS + } catch (...) { + __other.clear(); + throw; +# endif // _LIBCPP_HAS_EXCEPTIONS + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(__first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert(sorted_unique, __first, __last); + } + + template + requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, + _InputIterator __first, + _InputIterator __last, + const key_compare& __comp, + const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert(sorted_unique, __first, __last); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { + insert_range(std::forward<_Range>(__rg)); + } + + template <_ContainerCompatibleRange _Range, class _Allocator> + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { + insert_range(std::forward<_Range>(__rg)); + } + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) + : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(initializer_list __il) { + clear(); + insert(__il); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(const flat_set&) = default; + + _LIBCPP_HIDE_FROM_ABI flat_set& operator=(flat_set&& __other) noexcept( + is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_Compare>) { + // No matter what happens, we always want to clear the other container before returning + // since we moved from it + auto __clear_other_guard = std::__make_scope_guard([&]() noexcept { __other.clear() /* noexcept */; }); + { + // If an exception is thrown, we have no choice but to clear *this to preserve invariants + auto __on_exception = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__other.__keys_); + __compare_ = std::move(__other.__compare_); + __on_exception.__complete(); + } + return *this; + } + + // iterators + _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } + + _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } + + _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + + _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return begin(); } + _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return end(); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + // [flat.set.capacity], capacity + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __keys_.empty(); } + + _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __keys_.size(); } + + _LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept { return __keys_.max_size(); } + + // [flat.set.modifiers], modifiers + template + _LIBCPP_HIDE_FROM_ABI pair emplace(_Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __try_emplace(std::forward<_Args>(__args)...); + } else { + return __try_emplace(_Key(std::forward<_Args>(__args)...)); + } + } + + template + _LIBCPP_HIDE_FROM_ABI iterator emplace_hint(const_iterator __hint, _Args&&... __args) { + if constexpr (sizeof...(__args) == 1 && (is_same_v, _Key> && ...)) { + return __emplace_hint(std::move(__hint), std::forward<_Args>(__args)...); + } else { + return __emplace_hint(std::move(__hint), _Key(std::forward<_Args>(__args)...)); + } + } + + _LIBCPP_HIDE_FROM_ABI pair insert(const value_type& __x) { return emplace(__x); } + + _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { + return emplace(std::forward<_Kp>(__x)); + } + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, const value_type& __x) { + return emplace_hint(__hint, __x); + } + + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, value_type&& __x) { + return emplace_hint(__hint, std::move(__x)); + } + + template + requires(__is_compare_transparent && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { + return emplace_hint(__hint, std::forward<_Kp>(__x)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template + requires __has_input_iterator_category<_InputIterator>::value + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, _InputIterator __first, _InputIterator __last) { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { + __reserve(__last - __first); + } + + __append_sort_merge_unique(std::move(__first), std::move(__last)); + } + + template <_ContainerCompatibleRange _Range> + _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { + if constexpr (ranges::sized_range<_Range>) { + __reserve(ranges::size(__range)); + } + + __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + } + + _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } + + _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, initializer_list __il) { + insert(sorted_unique, __il.begin(), __il.end()); + } + + _LIBCPP_HIDE_FROM_ABI container_type extract() && { + auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; }); + auto __ret = std::move(__keys_); + return __ret; + } + + _LIBCPP_HIDE_FROM_ABI void replace(container_type&& __keys) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __is_sorted_and_unique(__keys), "Either the key container is not sorted or it contains duplicates"); + auto __guard = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + __keys_ = std::move(__keys); + __guard.__complete(); + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __position) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_iter = __keys_.erase(__position); + __on_failure.__complete(); + return __key_iter; + } + + // The following overload is the same as the iterator overload + // iterator erase(const_iterator __position); + + _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __x) { + auto __iter = find(__x); + if (__iter != end()) { + erase(__iter); + return 1; + } + return 0; + } + + template + requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + !is_convertible_v<_Kp &&, const_iterator>) + _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { + auto [__first, __last] = equal_range(__x); + auto __res = __last - __first; + erase(__first, __last); + return __res; + } + + _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + auto __key_it = __keys_.erase(__first, __last); + __on_failure.__complete(); + return __key_it; + } + + _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __y) noexcept { + // warning: The spec has unconditional noexcept, which means that + // if any of the following functions throw an exception, + // std::terminate will be called. + // This is discussed in P2767, which hasn't been voted on yet. + ranges::swap(__compare_, __y.__compare_); + ranges::swap(__keys_, __y.__keys_); + } + + _LIBCPP_HIDE_FROM_ABI void clear() noexcept { __keys_.clear(); } + + // observers + _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __compare_; } + _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __compare_; } + + // set operations + _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __x) { return __find_impl(*this, __x); } + + _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { + return __find_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { + return __find_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { + return contains(__x) ? 1 : 0; + } + + _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { + return find(__x) != end(); + } + + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { + return ranges::lower_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { + return ranges::upper_bound(__keys_, __x, __compare_); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) { + return __equal_range_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) const { + return __equal_range_impl(*this, __x); + } + + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { + return __equal_range_impl(*this, __x); + } + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { + return __equal_range_impl(*this, __x); + } + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const flat_set& __x, const flat_set& __y) { + return ranges::equal(__x, __y); + } + + friend _LIBCPP_HIDE_FROM_ABI auto operator<=>(const flat_set& __x, const flat_set& __y) { + return std::lexicographical_compare_three_way( + __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); + } + + friend _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __x, flat_set& __y) noexcept { __x.swap(__y); } + +private: + struct __ctor_uses_allocator_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_tag() = default; + }; + struct __ctor_uses_allocator_empty_tag { + explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_empty_tag() = default; + }; + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI + flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), + __compare_(std::forward<_CompArg>(__comp)...) {} + + template + requires __allocator_ctor_constraint<_Allocator> + _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) + : __keys_(std::make_obj_using_allocator(__alloc)), + __compare_(std::forward<_CompArg>(__comp)...) {} + + _LIBCPP_HIDE_FROM_ABI bool __is_sorted_and_unique(auto&& __key_container) const { + auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) { return !__compare_(__x, __y); }; + return ranges::adjacent_find(__key_container, __greater_or_equal_to) == ranges::end(__key_container); + } + + // This function is only used in constructors. So there is not exception handling in this function. + // If the function exits via an exception, there will be no flat_set object constructed, thus, there + // is no invariant state to preserve + _LIBCPP_HIDE_FROM_ABI void __sort_and_unique() { + ranges::sort(__keys_, __compare_); + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } else { + for (; __first != __last; ++__first) { + __keys_.insert(__keys_.end(), *__first); + } + } + if (size() != __old_size) { + if constexpr (!_WasSorted) { + ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); + } else { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__is_sorted_and_unique(__keys_ | ranges::views::drop(__old_size)), + "Either the key container is not sorted or it contains duplicates"); + } + ranges::inplace_merge(__keys_.begin(), __keys_.begin() + __old_size, __keys_.end(), __compare_); + + auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin(); + __keys_.erase(__dup_start, __keys_.end()); + } + __on_failure.__complete(); + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __find_impl(_Self&& __self, const _Kp& __key) { + auto __it = __self.lower_bound(__key); + auto __last = __self.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return __last; + } + return __it; + } + + template + _LIBCPP_HIDE_FROM_ABI static auto __equal_range_impl(_Self&& __self, const _Kp& __key) { + auto __it = ranges::lower_bound(__self.__keys_, __key, __self.__compare_); + auto __last = __self.__keys_.end(); + if (__it == __last || __self.__compare_(__key, *__it)) { + return std::make_pair(__it, __it); + } + return std::make_pair(__it, std::next(__it)); + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_exact_pos(const_iterator __it, _KeyArg&& __key) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { + if constexpr (!__container_traits<_KeyContainer>::__emplacement_has_strong_exception_safety_guarantee) { + clear() /* noexcept */; + } + }); + auto __key_it = __keys_.emplace(__it, std::forward<_KeyArg>(__key)); + __on_failure.__complete(); + return __key_it; + } + + template + _LIBCPP_HIDE_FROM_ABI pair __try_emplace(_Kp&& __key) { + auto __it = lower_bound(__key); + if (__it == end() || __compare_(__key, *__it)) { + return pair(__emplace_exact_pos(__it, std::forward<_Kp>(__key)), true); + } else { + return pair(std::move(__it), false); + } + } + + template + _LIBCPP_HIDE_FROM_ABI bool __is_hint_correct(const_iterator __hint, _Kp&& __key) { + if (__hint != cbegin() && !__compare_(*(__hint - 1), __key)) { + return false; + } + if (__hint != cend() && __compare_(*__hint, __key)) { + return false; + } + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint(const_iterator __hint, _Kp&& __key) { + if (__is_hint_correct(__hint, __key)) { + if (__hint == cend() || __compare_(__key, *__hint)) { + return __emplace_exact_pos(__hint, std::forward<_Kp>(__key)); + } else { + // key equals + return __hint; + } + } else { + return __try_emplace(std::forward<_Kp>(__key)).first; + } + } + + _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __size) { + if constexpr (requires { __keys_.reserve(__size); }) { + __keys_.reserve(__size); + } + } + + template + friend typename flat_set<_Key2, _Compare2, _KeyContainer2>::size_type + erase_if(flat_set<_Key2, _Compare2, _KeyContainer2>&, _Predicate); + + _KeyContainer __keys_; + _LIBCPP_NO_UNIQUE_ADDRESS key_compare __compare_; + + struct __key_equiv { + _LIBCPP_HIDE_FROM_ABI __key_equiv(key_compare __c) : __comp_(__c) {} + _LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const { + return !__comp_(__x, __y) && !__comp_(__y, __x); + } + key_compare __comp_; + }; +}; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(_KeyContainer, _Compare = _Compare()) -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(_KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(_KeyContainer, _Compare, _Allocator) -> flat_set; + +template > + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare = _Compare()) + -> flat_set; + +template + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) +flat_set(sorted_unique_t, _KeyContainer, _Allocator) + -> flat_set, _KeyContainer>; + +template + requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + uses_allocator_v<_KeyContainer, _Allocator> && + is_invocable_v) +flat_set(sorted_unique_t, _KeyContainer, _Compare, _Allocator) + -> flat_set; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(_InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + +template >, + class _Allocator = allocator, + class = __enable_if_t::value && __is_allocator<_Allocator>::value>> +flat_set(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> flat_set< + ranges::range_value_t<_Range>, + _Compare, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template ::value>> +flat_set(from_range_t, _Range&&, _Allocator) -> flat_set< + ranges::range_value_t<_Range>, + less>, + vector, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template > + requires(!__is_allocator<_Compare>::value) +flat_set(sorted_unique_t, initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template +struct uses_allocator, _Allocator> + : bool_constant> {}; + + template + _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type + erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; + } + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FLAT_set_FLAT_SET_H diff --git a/libcxx/include/flat_set b/libcxx/include/flat_set new file mode 100644 index 00000000000000..d03645fafafdba --- /dev/null +++ b/libcxx/include/flat_set @@ -0,0 +1,59 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_FLAT_SET +#define _LIBCPP_FLAT_SET + +/* + Header synopsis + +#include // see [compare.syn] +#include // see [initializer.list.syn] + +namespace std { + // [flat.set], class template flat_set + template, class KeyContainer = vector> + class flat_set; + + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + + template + struct uses_allocator, Allocator>; + + // [flat.set.erasure], erasure for flat_set + template + typename flat_set::size_type + erase_if(flat_set& c, Predicate pred); +} +*/ + +#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +# include <__cxx03/__config> +#else +# include <__config> + +# if _LIBCPP_STD_VER >= 23 +# include <__flat_map/sorted_unique.h> +# include <__flat_set/flat_set.h> +# endif + +// for feature-test macros +# include + +// standard required includes +# include +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif +#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) + +#endif // _LIBCPP_FLAT_SET diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4bae02137b37b2..abc351d5923963 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1263,6 +1263,17 @@ module std [system] { export * } + module flat_set { + module flat_set { + header "__flat_set/flat_set.h" + export std.vector.vector + export std.vector.fwd + } + + header "flat_set" + export * + } + module format { module buffer { header "__format/buffer.h" diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp new file mode 100644 index 00000000000000..204df1d681af1b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m; + ASSERT_SAME_TYPE(decltype(m.empty()), bool); + ASSERT_NOEXCEPT(m.empty()); + assert(m.empty()); + assert(std::as_const(m).empty()); + m = {1}; + assert(!m.empty()); + m.clear(); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp new file mode 100644 index 00000000000000..161fe533eabacb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.verify.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [[nodiscard]] bool empty() const noexcept; + +#include + +void f() { + std::flat_set c; + c.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp new file mode 100644 index 00000000000000..cd7f424e00ece2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type max_size() const noexcept; + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_allocator.h" +#include "test_macros.h" + +int main(int, char**) { + { + using A1 = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= 10); + LIBCPP_ASSERT(c.max_size() == 10); + } + { + using A = limited_allocator; + using C = std::flat_set, std::vector>; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + LIBCPP_ASSERT(c.max_size() == max_dist); + } + { + typedef std::flat_set C; + ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t); + ASSERT_SAME_TYPE(C::size_type, std::size_t); + const C::size_type max_dist = static_cast(std::numeric_limits::max()); + const C c; + ASSERT_NOEXCEPT(c.max_size()); + ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type); + assert(c.max_size() <= max_dist); + assert(c.max_size() <= alloc_max_size(std::allocator())); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp new file mode 100644 index 00000000000000..7c156e95ecb1c8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type size() const noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using M = std::flat_set, KeyContainer>; + using S = typename M::size_type; + { + const M m = {1, 1, 4, 5, 5}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 3); + } + { + const M m = {1}; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 1); + } + { + const M m; + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == 0); + } + { + M m; + S s = 1000000; + for (auto i = 0u; i < s; ++i) { + m.emplace(i); + } + ASSERT_SAME_TYPE(decltype(m.size()), S); + ASSERT_NOEXCEPT(m.size()); + assert(m.size() == s); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp new file mode 100644 index 00000000000000..acc0817d7cac4d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// explicit flat_set(const Allocator& a); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // explicit + using M = std::flat_set, std::vector>>; + + static_assert(std::is_constructible_v>); + static_assert(!std::is_convertible_v, M>); + } + { + using A = test_allocator; + using M = std::flat_set, std::vector>>; + M m(A(0, 5)); + assert(m.empty()); + assert(m.begin() == m.end()); + auto v = std::move(m).extract(); + assert(v.get_allocator().get_id() == 5); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp new file mode 100644 index 00000000000000..7f75f1e1611e3b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(initializer_list il); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m = {8, 10}; + assert(m.size() == 2); + m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + int expected[] = {1, 2, 3, 4, 5, 6}; + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + } + { + M m = {10, 8}; + assert(m.size() == 2); + m = {3}; + int expected[] = {3}; + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp new file mode 100644 index 00000000000000..b3bee18f5a936b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(const key_compare& comp); +// template +// flat_set(const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + auto m = std::flat_set(C(3)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(3)); + } + { + // The one-argument ctor is explicit. + using C = test_less; + static_assert(std::is_constructible_v, C>); + static_assert(!std::is_convertible_v>); + + static_assert(std::is_constructible_v, std::less>); + static_assert(!std::is_convertible_v, std::flat_set>); + } + { + using C = test_less; + using A1 = test_allocator; + auto m = std::flat_set>(C(4), A1(5)); + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + { + // explicit(false) + using C = test_less; + using A1 = test_allocator; + std::flat_set> m = {C(4), A1(5)}; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp() == C(4)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp new file mode 100644 index 00000000000000..3d1e6240c952e8 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -0,0 +1,158 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// explicit flat_set(container_type key_cont, const key_compare& comp = key_compare()); +// template +// flat_set(const container_type& key_cont, const Allocator& a); +// template +// flat_set(const container_type& key_cont, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(container_type) + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + + // explicit + static_assert(std::is_constructible_v&>); + static_assert(!ImplicitlyConstructible&>); + } + { + // flat_set(container_type) + // move-only + MoveOnly expected[] = {3, 2, 1}; + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks; + ks.push_back(1); + ks.push_back(3); + ks.push_back(2); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(container_type) + // container's allocator is used + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(5)); + } + { + // flat_set(container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + + // explicit + static_assert(std::is_constructible_v&, const C&>); + static_assert(!ImplicitlyConstructible&, const C&>); + } + { + // flat_set(container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + auto m = M(ks, A(4)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , const Allocator&) + // explicit(false) + using A = test_allocator; + using M = std::flat_set, std::deque>; + static_assert(ImplicitlyConstructible&, const A&>); + auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); + M m = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 3})); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(4)); + } + { + // flat_set(container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + auto m = M(ks, C(4), A(5)); + assert(std::ranges::equal(m, std::vector{1, 2, 3})); + assert(m.key_comp() == C(4)); + auto m_copy = m; + auto keys = std::move(m_copy).extract(); + assert(keys.get_allocator() == A(5)); + + // explicit(false) + static_assert(ImplicitlyConstructible&, const A&>); + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + keys = std::move(m2).extract(); + assert(keys.get_allocator() == A(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp new file mode 100644 index 00000000000000..f1dbc955e1b0de --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(-2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp new file mode 100644 index 00000000000000..59fb9d0a38366f --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(const flat_set&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M(mo, test_allocator(3)); + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(3)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp new file mode 100644 index 00000000000000..169b469f3bca68 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& s); + +// Validate whether the container can be copy-assigned (move-assigned, swapped) +// with an ADL-hijacking operator& + +#include +#include + +#include "test_macros.h" +#include "operator_hijacker.h" + +void test() { + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp new file mode 100644 index 00000000000000..cdd5045f4bb9f7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(const flat_set& m); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // test_allocator is not propagated + using C = test_less; + std::vector> ks({1, 3, 5}, test_allocator(6)); + using M = std::flat_set; + auto mo = M(ks, C(5)); + auto m = M({{3, 4, 5}}, C(3), test_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == test_allocator(2)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == test_allocator(6)); + } + { + // other_allocator is propagated + using C = test_less; + using Ks = std::vector>; + auto ks = Ks({1, 3, 5}, other_allocator(6)); + using M = std::flat_set; + auto mo = M(Ks(ks, other_allocator(6)), C(5)); + auto m = M({3, 4, 5}, C(3), other_allocator(2)); + m = mo; + + assert(m.key_comp() == C(5)); + assert(std::ranges::equal(m, ks)); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == other_allocator(6)); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert(std::ranges::equal(mo, ks)); + auto keys2 = std::move(mo).extract(); + assert(keys2.get_allocator() == other_allocator(6)); + } + { + // comparator is copied and invariant is preserved + using M = std::flat_set>; + M mo = M({1, 2}, std::less()); + M m = M({1, 2}, std::greater()); + assert(m.key_comp()(2, 1) == true); + assert(m != mo); + m = mo; + assert(m.key_comp()(2, 1) == false); + assert(m == mo); + } + { + // self-assignment + using M = std::flat_set; + M m = {{1, 2}}; + m = static_cast(m); + assert((m == M{{1, 2}})); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp new file mode 100644 index 00000000000000..5db8c4ca722466 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Test CTAD on cases where deduction should fail. + +#include +#include +#include +#include +#include + +struct NotAnAllocator { + friend bool operator<(NotAnAllocator, NotAnAllocator) { return false; } +}; + +template +concept CanDeductFlatSet = requires { std::flat_set{std::declval()...}; }; + +static_assert(CanDeductFlatSet, std::vector>); + +// cannot deduce Key and T from nothing +static_assert(!CanDeductFlatSet<>); + +// cannot deduce Key and T from just (KeyContainer), even if it's a container of pairs +static_assert(!CanDeductFlatSet>>); + +// cannot deduce Key and T from just (KeyContainer, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>>); + +// cannot deduce Key and T from just (Compare) +static_assert(!CanDeductFlatSet>); + +// cannot deduce Key and T from just (Compare, Allocator) +static_assert(!CanDeductFlatSet, std::allocator>); + +// cannot deduce Key and T from just (Allocator) +static_assert(!CanDeductFlatSet>); + +// cannot convert from some arbitrary unrelated type +static_assert(!CanDeductFlatSet); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp new file mode 100644 index 00000000000000..612e64a7c42f23 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -0,0 +1,341 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "deduction_guides_sfinae_checks.h" +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_copy() { + { + std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set s(source); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s{source}; // braces instead of parens + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } + { + std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set s(source, std::allocator()); + ASSERT_SAME_TYPE(decltype(s), decltype(source)); + assert(s == source); + } +} + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(ks, vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(ks, vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 43); + } + { + std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } + { + std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 44); + assert(s.values().get_allocator().get_id() == 44); + } +} + +void test_iter_iter() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m(std::begin(arr), std::end(arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend()); + ASSERT_SAME_TYPE(decltype(m), decltype(mo)); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } + { + std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) + static_assert(std::is_same_v>); + assert(s.size() == 3); + } +} + +void test_iter_iter_compare() { + const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m(std::begin(arr), std::end(arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } +} + +void test_initializer_list() { + const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + { + std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } + { + using M = std::flat_set; + M m; + std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + assert(s[m] == m); + } +} + +void test_initializer_list_compare() { + const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + using C = std::greater; + { + std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } +} + +void test_from_range() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + { + std::flat_set s(std::from_range, r); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +void test_from_range_compare() { + std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + { + std::flat_set s(std::from_range, r, std::greater()); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + ASSERT_SAME_TYPE( + decltype(s), + std::flat_set, + std::vector>, + std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(s.keys().get_allocator().get_id() == 42); + assert(s.values().get_allocator().get_id() == 42); + } +} + +int main(int, char**) { + // Each test function also tests the sorted_unique-prefixed and allocator-suffixed overloads. + test_copy(); + test_containers(); + test_containers_compare(); + test_iter_iter(); + test_iter_iter_compare(); + test_initializer_list(); + test_initializer_list_compare(); + test_from_range(); + test_from_range_compare(); + + AssociativeContainerDeductionGuidesSfinaeAway>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp new file mode 100644 index 00000000000000..df8d6d885ee524 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_allocator.h" + +using P = std::pair; +using PC = std::pair; + +void test_containers() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); + const int expected[] = {1, 2, 3, INT_MAX}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +void test_containers_compare() { + std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); + std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); + const int expected[] = {INT_MAX, 3, 2, 1}; + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(ks.begin(), ks.end(), &mr); + std::flat_set s(std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } + { + std::pmr::monotonic_buffer_resource mr; + std::pmr::monotonic_buffer_resource mr2; + std::pmr::deque pks(sorted_ks.begin(), sorted_ks.end(), &mr); + std::flat_set s(std::sorted_unique, std::move(pks), std::greater(), &mr2); + + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::pmr::deque>); + assert(std::ranges::equal(s, expected)); + auto keys = std::move(s).extract(); + assert(keys.get_allocator().resource() == &mr2); + } +} + +int main(int, char**) { + test_containers(); + test_containers_compare(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp new file mode 100644 index 00000000000000..64b0bfcb383a72 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + std::flat_set m; + assert(m.empty()); + } + { + // explicit(false) + std::flat_set m = {}; + assert(m.empty()); + } + { + std::flat_set>> m; + assert(m.empty()); + assert(m.begin() == m.end()); + assert(m.key_comp().default_constructed_); + } + { + using A1 = explicit_allocator; + using A2 = explicit_allocator; + { + std::flat_set> m; + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + { + A1 a1; + std::flat_set> m(a1); + assert(m.empty()); + assert(m.key_comp().default_constructed_); + } + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp new file mode 100644 index 00000000000000..b4a3b6de205a31 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set() +// noexcept( +// is_nothrow_default_constructible_v && +// is_nothrow_default_constructible_v); + +// This tests a conforming extension + +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +int main(int, char**) { +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp new file mode 100644 index 00000000000000..c0d315c0ce74b4 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// ~flat_set(); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +struct ThrowingDtorComp { + bool operator()(const auto&, const auto&) const; + ~ThrowingDtorComp() noexcept(false) {} +}; + +int main(int, char**) { + { + using C = std::flat_set; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::vector>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } + { + using V = std::deque>; + using C = std::flat_set, V>; + static_assert(std::is_nothrow_destructible_v); + C c; + } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(!std::is_nothrow_destructible_v); + C c; + } +#endif // _LIBCPP_VERSION + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp new file mode 100644 index 00000000000000..cd2319e91f760d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -0,0 +1,151 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(initializer_list il, const key_compare& comp = key_compare()); +// template +// flat_set(initializer_list il, const Alloc& a); +// template +// flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +#include "../../../test_compare.h" + +struct DefaultCtableComp { + explicit DefaultCtableComp() { default_constructed_ = true; } + bool operator()(int, int) const { return false; } + bool default_constructed_ = false; +}; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert(!std::is_constructible_v, C, std::allocator>); + static_assert(!std::is_constructible_v, std::allocator>); + } + + int expected[] = {1, 2, 3, 5}; + { + // flat_set(initializer_list); + using M = std::flat_set; + std::initializer_list il = {5, 2, 2, 3, 1, 3}; + M m(il); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + // explicit(false) + using M = std::flat_set; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + } + { + // flat_set(initializer_list); + using M = std::flat_set, std::deque>>; + M m = {5, 2, 2, 3, 1, 3}; + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + { + using A = explicit_allocator; + { + // flat_set(initializer_list); + // different comparator + using M = std::flat_set>; + M m = {1, 2, 3}; + assert(m.size() == 1); + LIBCPP_ASSERT(*m.begin() == 1); + assert(m.key_comp().default_constructed_); + } + { + // flat_set(initializer_list, const Allocator&); + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + } + { + // flat_set(initializer_list, const key_compare&); + using C = test_less; + using M = std::flat_set; + auto m = M({5, 2, 2, 3, 1, 3}, C(10)); + assert(std::equal(m.begin(), m.end(), expected, expected + 4)); + assert(m.key_comp() == C(10)); + + // explicit(false) + M m2 = {{5, 2, 2, 1, 3, 3}, C(10)}; + assert(m2 == m); + assert(m2.key_comp() == C(10)); + } + { + // flat_set(initializer_list, const key_compare&); + // Sorting uses the comparator that was passed in + using M = std::flat_set, std::deque>>; + auto m = M({5, 2, 2, 1, 3, 1}, std::greater()); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + assert(m.key_comp()(2, 1) == true); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using A = explicit_allocator; + using M = std::flat_set, std::deque>; + A a; + M m({5, 2, 2, 3, 1, 3}, {}, a); + assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp new file mode 100644 index 00000000000000..65eebc21a66c4c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(InputIterator first, InputIterator last, const Allocator& a); +// template +// flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(InputIterator , InputIterator) + // cpp17_input_iterator + using M = std::flat_set; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)}; + assert(m2 == m); + } + { + // flat_set(InputIterator , InputIterator) + // greater + using M = std::flat_set, std::deque>>; + auto m = M(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(InputIterator , InputIterator) + // Test when the operands are of array type (also contiguous iterator type) + using M = std::flat_set, std::vector>>; + auto m = M(ar, ar); + assert(m.empty()); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&) + using C = test_less; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {ar, ar + 9, C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + auto m = M(ar, ar + 9, A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + M m = {ar, ar + 9, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(ar, ar + 9, C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {ar, ar + 9, {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp new file mode 100644 index 00000000000000..69b340ad09fe15 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A(7)); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A(7)); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().get_id() == test_alloc_base::moved_value); + } + { + using C = test_less; + using A = min_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A()); + M m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + assert(std::move(m).extract().get_allocator() == A()); + + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A()); + } + { + // A moved-from flat_set maintains its class invariant in the presence of moved-from comparators. + using M = std::flat_set>; + M mo = M({1, 2, 3}, std::less()); + M m = std::move(mo); + assert(m.size() == 3); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.key_comp()(1, 2) == true); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + LIBCPP_ASSERT(m.key_comp()(1, 2) == true); + LIBCPP_ASSERT(mo.empty()); + mo.insert({1, 2, 3}); // insert has no preconditions + assert(m == mo); + } + { + // moved-from object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m1.size() == 0); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp new file mode 100644 index 00000000000000..fc7f68d8c967ad --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&, const allocator_type&); + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" +#include "../../../test_compare.h" +#include "test_allocator.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + int expected[] = {1, 2, 3}; + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + auto mo = M(expected, expected + 3, C(5), A(7)); + auto m = M(std::move(mo), A(3)); + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + auto keys = std::move(m).extract(); + assert(keys.get_allocator() == A(3)); + assert(std::ranges::equal(keys, expected )); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.empty()); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator() == A(7)); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m1 = M({1, 2, 3}); + M m2(std::move(m1), std::allocator{}); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp new file mode 100644 index 00000000000000..b16dc38dd40285 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "../../../test_compare.h" +#include "test_allocator.h" +#include "min_allocator.h" + +int main(int, char**) { + { + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{1, 2, 3})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + m = std::move(mo); + assert((m == M{4, 5})); + assert(m.key_comp() == C(5)); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A1(7)); + assert(mo.empty()); + } + { + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + m = std::move(mo); + assert((m == M{5, 4, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator() == A()); + assert(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp new file mode 100644 index 00000000000000..50817f4be8a812 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&&); +// Preserves the class invariant for the moved-from flat_set. + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +int main(int, char**) { + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp new file mode 100644 index 00000000000000..86f3568f0d67a6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set& operator=(flat_set&& c) +// noexcept( +// is_nothrow_move_assignable::value && +// is_nothrow_move_assignable::value && +// is_nothrow_copy_assignable::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_macros.h" + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp new file mode 100644 index 00000000000000..17e4e40387606c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// flat_set(flat_set&& s); +// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. + +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +int main(int, char**) { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp new file mode 100644 index 00000000000000..49d1151fd8a993 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(flat_set&&) +// noexcept(is_nothrow_move_constructible::value && +// is_nothrow_move_constructible::value && +// is_nothrow_copy_constructible::value); + +// This tests a conforming extension + +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +int main(int, char**) { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp new file mode 100644 index 00000000000000..785718d2eed333 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -0,0 +1,322 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: availability-pmr-missing + +// + +// Test various constructors with pmr + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" +#include "test_allocator.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // flat_set(const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::polymorphic_allocator pa = &mr; + auto m1 = M(pa); + assert(m1.empty()); + assert(std::move(m1).extract().get_allocator() == pa); + auto m2 = M(&mr); + assert(m2.empty()); + assert(std::move(m2).extract().get_allocator() == pa); + } + { + // flat_set(const key_compare& comp, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::greater()); + assert(vm[0] == M{}); + assert(vm[0].key_comp()(2, 1) == true); + assert(vm[0].value_comp()(2, 1) == true); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + // const Allocator& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + assert(ks.get_allocator().resource() != &mr); + vm.emplace_back(ks); + assert(ks.size() == 9); // ks' value is unchanged, since it was an lvalue above + assert((vm[0] == M{1, 2, 3})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(const flat_set&, const allocator_type&); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, C(5), &mr1); + M m = {mo, &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + auto keys = std::move(m).extract(); + assert((keys == std::pmr::vector{1, 2, 3})); + assert(keys.get_allocator().resource() == &mr2); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + auto keys2 = std::move(mo).extract(); + assert((keys2 == std::pmr::vector{1, 2, 3})); + assert(keys2.get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set&, const allocator_type&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::vector vs; + M m = {1, 2, 3}; + vs.push_back(m); + assert(vs[0] == m); + } + { + // flat_set& operator=(const flat_set& m); + // pmr allocator is not propagated + using M = std::flat_set, std::pmr::deque>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 2, 3}, &mr1); + M m = M({4, 5}, &mr2); + m = mo; + assert((m == M{1, 2, 3})); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // mo is unchanged + assert((mo == M{1, 2, 3})); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(const flat_set& m); + using C = test_less; + std::pmr::monotonic_buffer_resource mr; + using M = std::flat_set>; + auto mo = M({1, 2, 3}, C(5), &mr); + auto m = mo; + + assert(m.key_comp() == C(5)); + assert((m == M{1, 2, 3})); + auto ks = std::move(m).extract(); + assert(ks.get_allocator().resource() == std::pmr::get_default_resource()); + + // mo is unchanged + assert(mo.key_comp() == C(5)); + assert((mo == M{1, 2, 3})); + auto kso = std::move(mo).extract(); + assert(kso.get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(initializer_list il, const key_compare& comp, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::initializer_list il = {3, 1, 4, 1, 5}; + vm.emplace_back(il, C(5)); + assert((vm[0] == M{1, 3, 4, 5})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + assert(vm[0].key_comp() == C(5)); + } + { + // flat_set(InputIterator first, InputIterator last, const Allocator& a); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // cpp17 iterator + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(cpp17_input_iterator(ar), cpp17_input_iterator(ar + 9)); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(ar, ar); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(flat_set&&, const allocator_type&); + int expected[] = {1, 2, 3}; + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = M({1, 3, 1, 2}, C(5), &mr1); + M m = {std::move(mo), &mr2}; // also test the implicitness of this constructor + + assert(m.key_comp() == C(5)); + assert(m.size() == 3); + assert(std::equal(m.begin(), m.end(), expected, expected + 3)); + assert(std::move(m).extract().get_allocator().resource() == &mr2); + + // The original flat_set is moved-from. + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + assert(mo.key_comp() == C(5)); + assert(std::move(mo).extract().get_allocator().resource() == &mr1); + } + { + // flat_set(flat_set&&, const allocator_type&); + using M = std::flat_set, std::pmr::deque>; + std::pmr::vector vs; + M m = {1, 3, 1, 2}; + vs.push_back(std::move(m)); + assert((std::move(vs[0]).extract() == std::pmr::deque{1, 2, 3})); + } + { + // flat_set& operator=(flat_set&&); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr1; + std::pmr::monotonic_buffer_resource mr2; + M mo = + M({"short", "very long string that definitely won't fit in the SSO buffer and therefore becomes empty on move"}, + &mr1); + M m = M({"don't care"}, &mr2); + m = std::move(mo); + assert(m.size() == 2); + assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); + assert(m.begin()->get_allocator().resource() == &mr2); + + assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); + mo.insert("foo"); + assert(mo.begin()->get_allocator().resource() == &mr1); + } + { + // flat_set(from_range_t, R&&, const Alloc&); + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // input_range + using M = std::flat_set, std::pmr::vector>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(vm[0], expected)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + using M = std::flat_set, std::pmr::vector>; + using R = std::ranges::subrange; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + vm.emplace_back(std::from_range, R(ar, ar)); + assert(vm[0].empty()); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + } + { + // flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks = {1, 2, 4, 10}; + vm.emplace_back(std::sorted_unique, ks); + assert(!ks.empty()); // it was an lvalue above + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, const container_type& key_cont,const Alloc& a); + using M = std::flat_set, std::pmr::vector>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + std::pmr::vector ks({1, 2, 4, 10}, &mr); + vm.emplace_back(std::sorted_unique, ks); + assert((vm[0] == M{1, 2, 4, 10})); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + // cpp_17 + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[] = {1, 2, 4, 5}; + vm.emplace_back( + std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4), C(3)); + assert((vm[0] == M{1, 2, 4, 5})); + assert(vm[0].key_comp() == C(3)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + { + // flat_set(InputIterator first, InputIterator last, const Alloc& a); + using C = test_less; + using M = std::flat_set>; + std::pmr::monotonic_buffer_resource mr; + std::pmr::vector vm(&mr); + int ar[1] = {42}; + vm.emplace_back(std::sorted_unique, ar, ar, C(4)); + assert(vm[0] == M{}); + assert(vm[0].key_comp() == C(4)); + assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp new file mode 100644 index 00000000000000..bb9f99c228bfec --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -0,0 +1,173 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// flat_set(from_range_t, R&&) +// template R> +// flat_set(from_range_t, R&&, const key_compare&) +// template R, class Alloc> +// flat_set(from_range_t, R&&, const Alloc&); +// template R, class Alloc> +// flat_set(from_range_t, R&&, const key_compare&, const Alloc&); + +#include +#include +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +// test constraint container-compatible-range + +template +using RangeOf = std::ranges::subrange; +using Set = std::flat_set; + +static_assert(std::is_constructible_v>); +static_assert(std::is_constructible_v>); +static_assert(!std::is_constructible_v>>); + +static_assert(std::is_constructible_v, std::less>); +static_assert(std::is_constructible_v, std::less>); +static_assert(!std::is_constructible_v>, std::less>); + +static_assert(std::is_constructible_v, std::allocator>); +static_assert(std::is_constructible_v, std::allocator>); +static_assert(!std::is_constructible_v>, std::allocator>); + +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert(std::is_constructible_v, std::less, std::allocator>); +static_assert( + !std:: + is_constructible_v>, std::less, std::allocator>); + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + + int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3}; + int expected[] = {1, 2, 3}; + { + // flat_set(from_range_t, R&&) + // input_range && !common + using M = std::flat_set; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, expected)); + LIBCPP_ASSERT(std::ranges::equal(m, expected)); + + // explicit(false) + M m2 = {std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))}; + assert(m2 == m); + } + { + // flat_set(from_range_t, R&&) + // greater + using M = std::flat_set, std::deque>>; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); + assert(std::ranges::equal(m, std::deque>{3, 2, 1})); + } + { + // flat_set(from_range_t, R&&) + // contiguous range + using M = std::flat_set; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9)); + assert(std::ranges::equal(m, expected)); + } + { + // flat_set(from_range_t, R&&, const key_compare&) + using C = test_less; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + + // explicit(false) + M m2 = {std::from_range, R(ar, ar + 9), C(3)}; + assert(m2 == m); + assert(m2.key_comp() == C(3)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + using R = std::ranges::subrange; + auto m = M(std::from_range, R(ar, ar + 9), C(3), A1(5)); + assert(std::ranges::equal(m, expected)); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(from_range_t, R&&, const key_compare&, const Allocator&) + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + using R = std::ranges::subrange; + M m = {std::from_range, R(ar, ar + 9), {}, A1(5)}; // implicit ctor + assert(std::ranges::equal(m, expected)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp new file mode 100644 index 00000000000000..2d442d49667bd0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set(sorted_unique_t, container_type key_cont, const key_compare& comp = key_compare()); +// +// template +// flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a); +// template +// flat_set(sorted_unique_t, const container_type& key_cont, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "MoveOnly.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, container_type) + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + auto ks2 = ks; + + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + + // explicit(false) + M m2 = {std::sorted_unique, std::move(ks2)}; + assert(m == m2); + } + { + // flat_set(sorted_unique_t, container_type) + // non-default container, comparator and allocator type + using Ks = std::deque>; + using M = std::flat_set, Ks>; + Ks ks = {10, 4, 2, 1}; + auto m = M(std::sorted_unique, ks); + assert((m == M{1, 2, 4, 10})); + m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + } + { + // flat_set(sorted_unique_t, container_type) + // allocator copied into the containers + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, std::move(ks)); + assert(ks.empty()); // it was moved-from + assert((m == M{1, 2, 4, 10})); + assert(std::move(m).extract().get_allocator() == A(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare) + using C = test_less; + using M = std::flat_set; + std::vector ks = {1, 2, 4, 10}; + + auto m = M(std::sorted_unique, ks, C(4)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, C(4)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + } + { + // flat_set(sorted_unique_t, container_type , key_compare, const Allocator&) + using C = test_less; + using A = test_allocator; + using M = std::flat_set>; + std::vector ks = {1, 2, 4, 10}; + auto m = M(std::sorted_unique, ks, C(4), A(5)); + assert((m == M{1, 2, 4, 10})); + assert(m.key_comp() == C(4)); + assert(M(m).extract().get_allocator() == A(5)); + + // explicit(false) + M m2 = {ks, C(4), A(5)}; + assert(m2 == m); + assert(m2.key_comp() == C(4)); + assert(std::move(m2).extract().get_allocator() == A(5)); + } + { + // flat_set(sorted_unique_t, container_type , const Allocator&) + using A = test_allocator; + using M = std::flat_set, std::deque>; + auto ks = std::deque({1, 2, 4, 10}, A(4)); + auto m = M(std::sorted_unique, ks, A(6)); // replaces the allocators + assert(!ks.empty()); // it was an lvalue above + assert((m == M{1, 2, 4, 10})); + assert(M(m).extract().get_allocator() == A(6)); + + // explicit(false) + M m2 = {std::sorted_unique, ks, A(6)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A(6)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp new file mode 100644 index 00000000000000..01956a78c7f48d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t s, initializer_list il, +// const key_compare& comp = key_compare()) +// template +// flat_set(sorted_unique_t, initializer_list il, const Alloc& a); +// template +// flat_set(sorted_unique_t, initializer_list il, +// const key_compare& comp, const Alloc& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +template +std::initializer_list il = {1, 2, 4, 5}; + +const auto il1 = il; +const auto il2 = il; + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using IL = std::initializer_list; + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // initializer_list needs to match exactly + using M = std::flat_set; + using C = typename M::key_compare; + static_assert(std::is_constructible_v>); + static_assert(std::is_constructible_v, C>); + static_assert(std::is_constructible_v, C, std::allocator>); + static_assert(std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + static_assert(!std::is_constructible_v>); + static_assert(!std::is_constructible_v, C>); + static_assert( + !std::is_constructible_v, C, std::allocator>); + static_assert( + !std::is_constructible_v, std::allocator>); + } + + { + // flat_set(sorted_unique_t, initializer_list); + using M = std::flat_set; + auto m = M(std::sorted_unique, il1); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, il1}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + using M = std::flat_set>; + auto m = M(std::sorted_unique, il1, std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, il1, std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + std::initializer_list il4{5, 4, 2, 1}; + auto m = M(std::sorted_unique, il4, std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, initializer_list, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + auto m = M(std::sorted_unique, il2, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, il2, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + auto m = M(std::sorted_unique, il2, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, initializer_list, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + M m = {std::sorted_unique, il2, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp new file mode 100644 index 00000000000000..b5229a84dd5133 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp = key_compare()); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a); +// template +// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); + +#include +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../../../test_compare.h" + +int main(int, char**) { + { + // The constructors in this subclause shall not participate in overload + // resolution unless uses_allocator_v is true. + + using C = test_less; + using A1 = test_allocator; + using A2 = other_allocator; + using V1 = std::vector; + using V2 = std::vector; + using M1 = std::flat_set; + using M2 = std::flat_set; + using Iter1 = typename M1::iterator; + using Iter2 = typename M2::iterator; + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + static_assert(std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // cpp17_input_iterator + using M = std::flat_set; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + + // explicit(false) + M m2 = {std::sorted_unique, cpp17_input_iterator(ar), cpp17_input_iterator(ar + 4)}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // cpp_17_input_iterator + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()); + assert(m == M({1, 2, 4, 5}, std::less<>())); + assert(m.key_comp()(1, 2) == true); + + // explicit(false) + M m2 = {std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::less()}; + assert(m2 == m); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // greater + using M = std::flat_set, std::deque>>; + int ar[] = {5, 4, 2, 1}; + auto m = M(std::sorted_unique, + cpp17_input_iterator(ar), + cpp17_input_iterator(ar + 4), + std::greater()); + assert((m == M{5, 4, 2, 1})); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&); + // contiguous iterator + using C = test_less; + using M = std::flat_set>>; + int ar[1] = {42}; + auto m = M(std::sorted_unique, ar, ar, C(5)); + assert(m.empty()); + assert(m.key_comp() == C(5)); + } + { + // flat_set(sorted_unique_t, InputIterator , InputIterator, const Allocator&) + using A1 = test_allocator; + using M = std::flat_set, std::vector>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, A1(5)); + auto expected = M{1, 2, 4, 5}; + assert(m == expected); + assert(M(m).extract().get_allocator() == A1(5)); + + // explicit(false) + M m2 = {std::sorted_unique, ar, ar + 4, A1(5)}; + assert(m2 == m); + assert(std::move(m2).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + int ar[] = {1, 2, 4, 5}; + auto m = M(std::sorted_unique, ar, ar + 4, C(3), A1(5)); + assert((m == M{1, 2, 4, 5})); + assert(m.key_comp() == C(3)); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + { + // flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&); + // explicit(false) + using A1 = test_allocator; + using M = std::flat_set, std::deque>; + int ar[] = {1, 2, 4, 5}; + M m = {std::sorted_unique, ar, ar + 4, {}, A1(5)}; // implicit ctor + assert((m == M{1, 2, 4, 5})); + assert(std::move(m).extract().get_allocator() == A1(5)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp new file mode 100644 index 00000000000000..134db83aef3cad --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_allocator.h" +#include "min_allocator.h" + +// Verify that `flat_set` (like `set`) does NOT support std::erase. +// +template +concept HasStdErase = requires(S& s, typename S::value_type x) { std::erase(s, x); }; +static_assert(HasStdErase>); +static_assert(!HasStdErase>); + +template +M make(std::initializer_list vals) { + M ret; + for (int v : vals) + ret.emplace(v); + return ret; +} + +template +void test0( + std::initializer_list vals, Pred p, std::initializer_list expected, std::size_t expected_erased_count) { + M s = make(vals); + ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p))); + assert(expected_erased_count == std::erase_if(s, p)); + assert(s == make(expected)); +} + +template +void test() { + // Test all the plausible signatures for this predicate. + auto is1 = [](typename S::const_reference v) { return v == 1; }; + auto is2 = [](typename S::value_type v) { return v == 2; }; + auto is3 = [](const typename S::value_type& v) { return v == 3; }; + auto is4 = [](auto v) { return v == 4; }; + auto True = [](const auto&) { return true; }; + auto False = [](auto&&) { return false; }; + + test0({}, is1, {}, 0); + + test0({1}, is1, {}, 1); + test0({1}, is2, {1}, 0); + + test0({1, 2}, is1, {2}, 1); + test0({1, 2}, is2, {1}, 1); + test0({1, 2}, is3, {1, 2}, 0); + + test0({1, 2, 3}, is1, {2, 3}, 1); + test0({1, 2, 3}, is2, {1, 3}, 1); + test0({1, 2, 3}, is3, {1, 2}, 1); + test0({1, 2, 3}, is4, {1, 2, 3}, 0); + + test0({1, 2, 3}, True, {}, 3); + test0({1, 2, 3}, False, {1, 2, 3}, 0); +} + +int main(int, char**) { + test>(); + test, std::vector>>>(); + test, std::vector>>>(); + test, std::deque>>>(); + test, std::deque>>>(); + test>(); + test>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp new file mode 100644 index 00000000000000..6bbe1ad4f01670 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -0,0 +1,128 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions + +// + +// template +// typename flat_set::size_type +// erase_if(flat_set& c, Predicate pred); +// If any member function in [flat.set.defn] exits via an exception, the invariant is restored. +// (This is not a member function, but let's respect the invariant anyway.) + +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers.h" +#include "test_macros.h" + +struct Counter { + int c1, c2, throws; + void tick() { + c1 -= 1; + if (c1 == 0) { + c1 = c2; + throws += 1; + throw 42; + } + } +}; +Counter g_counter = {0, 0, 0}; + +struct ThrowingAssignment { + ThrowingAssignment(int i) : i_(i) {} + ThrowingAssignment(const ThrowingAssignment&) = default; + ThrowingAssignment& operator=(const ThrowingAssignment& rhs) { + g_counter.tick(); + i_ = rhs.i_; + g_counter.tick(); + return *this; + } + operator int() const { return i_; } + int i_; +}; + +struct ThrowingComparator { + bool operator()(const ThrowingAssignment& a, const ThrowingAssignment& b) const { + g_counter.tick(); + return a.i_ < b.i_; + } +}; + +struct ErasurePredicate { + bool operator()(const auto& x) const { return (3 <= x && x <= 5); } +}; + +int main(int, char**) { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + { + using M = std::flat_set; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + M m = M({1, 2, 3, 4, 5, 6, 7, 8}); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + + { + using M = std::flat_set>; + for (int first_throw = 1; first_throw < 99; ++first_throw) { + for (int second_throw = 1; second_throw < 99; ++second_throw) { + g_counter = {0, 0, 0}; + std::deque container = {5, 6, 7, 8}; + container.insert(container.begin(), {1, 2, 3, 4}); + M m = M(std::move(container)); + try { + g_counter = {first_throw, second_throw, 0}; + auto n = std::erase_if(m, ErasurePredicate()); + assert(n == 3); + // If it didn't throw at all, we're done. + g_counter = {0, 0, 0}; + assert((m == M{1, 2, 6, 7, 8})); + first_throw = 99; // "done" + break; + } catch (int ex) { + assert(ex == 42); + check_invariant(m); + LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8)); + if (g_counter.throws == 1) { + // We reached the first throw but not the second throw. + break; + } + } + } + } + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp new file mode 100644 index 00000000000000..c07297a141ad10 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator begin() noexcept; +// const_iterator begin() const noexcept +// iterator end() noexcept; +// const_iterator end() const noexcept; +// +// const_iterator cbegin() const noexcept; +// const_iterator cend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.begin()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cbegin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.begin()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(m.end()), typename M::iterator); + ASSERT_SAME_TYPE(decltype(m.cend()), typename M::const_iterator); + ASSERT_SAME_TYPE(decltype(cm.end()), typename M::const_iterator); + static_assert(noexcept(m.begin())); + static_assert(noexcept(cm.begin())); + static_assert(noexcept(m.cbegin())); + static_assert(noexcept(m.end())); + static_assert(noexcept(cm.end())); + static_assert(noexcept(m.cend())); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(std::distance(cm.begin(), cm.end()) == 4); + assert(std::distance(m.cbegin(), m.cend()) == 4); + typename M::iterator i; // default-construct + i = m.begin(); // move-assignment + typename M::const_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 1; j <= 4; ++j, ++i) { // pre-increment + assert(*i == j); // operator* + } + assert(i == m.end()); + for (int j = 4; j >= 1; --j) { + --i; // pre-decrement + assert((*i) == j); + } + assert(i == m.begin()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // N3644 testing + using C = std::flat_set; + C::iterator ii1{}, ii2{}; + C::iterator ii4 = ii1; + C::const_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp new file mode 100644 index 00000000000000..29441dcc57d40e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// flat_set iterators should be C++20 random access iterators + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using KI = typename KeyContainer::iterator; + using I = M::iterator; + using CI = M::const_iterator; + using RI = M::reverse_iterator; + using CRI = M::const_reverse_iterator; + + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + static_assert(std::equality_comparable); + + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + static_assert(std::totally_ordered); + + M m = {1, 2, 3, 4}; + + I i1 = m.begin(); + I i2 = m.begin() + 1; + + assert(i1 == i1); + assert(!(i1 != i1)); + assert(i1 != i2); + assert(!(i1 == i2)); + assert(i1 < i2); + assert(!(i1 < i1)); + assert(i1 <= i1); + assert(i1 <= i2); + assert(!(i2 <= i1)); + assert(i2 > i1); + assert(!(i2 > i2)); + assert(i2 >= i1); + assert(i2 >= i2); + assert(!(i1 >= i2)); + + CI ci1 = m.cbegin(); + CI ci2 = m.cbegin() + 1; + assert(ci1 == ci1); + assert(!(ci1 != ci1)); + assert(ci1 != ci2); + assert(!(ci1 == ci2)); + assert(ci1 < ci2); + assert(!(ci1 < ci1)); + assert(ci1 <= ci1); + assert(ci1 <= ci2); + assert(!(ci2 <= ci1)); + assert(ci2 > ci1); + assert(!(ci2 > ci2)); + assert(ci2 >= ci1); + assert(ci2 >= ci2); + assert(!(ci1 >= ci2)); + + RI ri1 = m.rbegin(); + RI ri2 = m.rbegin() + 1; + assert(ri1 == ri1); + assert(!(ri1 != ri1)); + assert(ri1 != ri2); + assert(!(ri1 == ri2)); + assert(ri1 < ri2); + assert(!(ri1 < ri1)); + assert(ri1 <= ri1); + assert(ri1 <= ri2); + assert(!(ri2 <= ri1)); + assert(ri2 > ri1); + assert(!(ri2 > ri2)); + assert(ri2 >= ri1); + assert(ri2 >= ri2); + assert(!(ri1 >= ri2)); + + CRI cri1 = m.crbegin(); + CRI cri2 = m.crbegin() + 1; + assert(cri1 == cri1); + assert(!(cri1 != cri1)); + assert(cri1 != cri2); + assert(!(cri1 == cri2)); + assert(cri1 < cri2); + assert(!(cri1 < cri1)); + assert(cri1 <= cri1); + assert(cri1 <= cri2); + assert(!(cri2 <= cri1)); + assert(cri2 > cri1); + assert(!(cri2 > cri2)); + assert(cri2 >= cri1); + assert(cri2 >= cri2); + assert(!(cri1 >= cri2)); + + if constexpr (std::three_way_comparable) { + static_assert(std::three_way_comparable); // ...of course the wrapped iterators still support <=>. + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::three_way_comparable); + static_assert(std::same_as I()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as CI()), std::strong_ordering>); + static_assert(std::same_as RI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + static_assert(std::same_as CRI()), std::strong_ordering>); + + assert(i1 <=> i1 == std::strong_ordering::equivalent); + assert(i1 <=> i2 == std::strong_ordering::less); + assert(i2 <=> i1 == std::strong_ordering::greater); + + assert(ci1 <=> ci1 == std::strong_ordering::equivalent); + assert(ci1 <=> ci2 == std::strong_ordering::less); + assert(ci2 <=> ci1 == std::strong_ordering::greater); + + assert(ri1 <=> ri1 == std::strong_ordering::equivalent); + assert(ri1 <=> ri2 == std::strong_ordering::less); + assert(ri2 <=> ri1 == std::strong_ordering::greater); + + assert(cri1 <=> cri1 == std::strong_ordering::equivalent); + assert(cri1 <=> cri2 == std::strong_ordering::less); + assert(cri2 <=> cri1 == std::strong_ordering::greater); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp new file mode 100644 index 00000000000000..35b45b6e797233 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator, const_iterator, reverse_iterator, const_reverse_iterator + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + using I = C::iterator; + using CI = C::const_iterator; + using RI = C::reverse_iterator; + using CRI = C::const_reverse_iterator; + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::contiguous_iterator); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(!std::indirectly_writable>); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(!std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::sentinel_for); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + static_assert(std::indirectly_movable_storable); + + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp new file mode 100644 index 00000000000000..4ec64e706b7021 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include +#include +#include +#include +#include +#include "MinSequenceContainer.h" +#include "min_allocator.h" + +template +void test() { + { + using Key = typename KeyContainer::value_type; + using C = std::flat_set, KeyContainer>; + + static_assert(std::same_as, typename C::iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(std::ranges::viewable_range); + + static_assert(std::same_as, typename C::const_iterator>); + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::view); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::borrowed_range); + static_assert(!std::ranges::viewable_range); + } +} + +void test() { + test>(); + test>(); + test>(); + test>>(); +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp new file mode 100644 index 00000000000000..a16383cdcf5383 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// reverse_iterator rbegin() noexcept; +// const_reverse_iterator rbegin() const noexcept; +// reverse_iterator rend() noexcept; +// const_reverse_iterator rend() const noexcept; +// +// const_reverse_iterator crbegin() const noexcept; +// const_reverse_iterator crend() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include + +#include "test_macros.h" +#include + +int main(int, char**) { + { + using M = std::flat_set, std::deque>; + M m = {1, 2, 3, 4}; + const M& cm = m; + ASSERT_SAME_TYPE(decltype(m.rbegin()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rbegin()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.rend()), M::reverse_iterator); + ASSERT_SAME_TYPE(decltype(m.crend()), M::const_reverse_iterator); + ASSERT_SAME_TYPE(decltype(cm.rend()), M::const_reverse_iterator); + static_assert(noexcept(m.rbegin())); + static_assert(noexcept(cm.rbegin())); + static_assert(noexcept(m.crbegin())); + static_assert(noexcept(m.rend())); + static_assert(noexcept(cm.rend())); + static_assert(noexcept(m.crend())); + assert(m.size() == 4); + assert(std::distance(m.rbegin(), m.rend()) == 4); + assert(std::distance(cm.rbegin(), cm.rend()) == 4); + assert(std::distance(m.crbegin(), m.crend()) == 4); + assert(std::distance(cm.crbegin(), cm.crend()) == 4); + M::reverse_iterator i; // default-construct + ASSERT_SAME_TYPE(decltype(*i), const int&); + i = m.rbegin(); // move-assignment + M::const_reverse_iterator k = i; // converting constructor + assert(i == k); // comparison + for (int j = 4; j >= 1; --j, ++i) { // pre-increment + assert(*i == j); + } + assert(i == m.rend()); + for (int j = 1; j <= 4; ++j) { + --i; // pre-decrement + assert(*i == j); + } + assert(i == m.rbegin()); + } + { + // N3644 testing + using C = std::flat_set; + C::reverse_iterator ii1{}, ii2{}; + C::reverse_iterator ii4 = ii1; + C::const_reverse_iterator cii{}; + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(!(ii1 != ii2)); + + assert((ii1 == cii)); + assert((cii == ii1)); + assert(!(ii1 != cii)); + assert(!(cii != ii1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp new file mode 100644 index 00000000000000..221a13fa057577 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// void clear() noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// test noexcept + +template +concept NoExceptClear = requires(T t) { + { t.clear() } noexcept; +}; + +static_assert(NoExceptClear>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptClear, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4, 5}; + assert(m.size() == 5); + ASSERT_NOEXCEPT(m.clear()); + ASSERT_SAME_TYPE(decltype(m.clear()), void); + m.clear(); + assert(m.size() == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp new file mode 100644 index 00000000000000..95f7a3c5f5d34a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -0,0 +1,141 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// pair emplace(Args&&... args); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the begin + M m = {3, 5, 6, 7}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted in the middle + M m = {0, 1, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 5); + assert(*r.first == 2); + } + { + // key does not exist and inserted at the end + M m = {0, 1}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } + { + // key already exists and original at the begin + M m = {2, 3, 5, 6}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original in the middle + M m = {0, 2, 3, 4}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 1); + assert(m.size() == 4); + assert(*r.first == 2); + } + { + // key already exists and original at the end + M m = {0, 1, 2}; + std::same_as decltype(auto) r = m.emplace(typename M::value_type(2)); + assert(!r.second); + assert(r.first == m.begin() + 2); + assert(m.size() == 3); + assert(*r.first == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace()), R); + R r = m.emplace(2, 0.0); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace(1, 3.5); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace(1, 3.5); + assert(!r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp new file mode 100644 index 00000000000000..de855d5e5c3009 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// iterator emplace_hint(const_iterator position, Args&&... args); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../../../Emplaceable.h" +#include "DefaultOnly.h" +#include "min_allocator.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + { + // was empty + M m; + std::same_as decltype(auto) r = m.emplace_hint(m.end(), typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + } + { + // hints correct at the begin + M m = {3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin()); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints correct at the end + M m = {0, 1}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints correct but key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin() + 2; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the begin + M m = {1, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrectly in the middle + M m = {0, 1, 3, 4}; + auto hint = m.begin() + 1; + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } + { + // hints incorrectly at the end + M m = {0, 3}; + auto hint = m.end(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 1); + assert(m.size() == 3); + assert(*r == 2); + } + { + // hints incorrect and key already exists + M m = {0, 1, 2, 3, 4}; + auto hint = m.begin(); + std::same_as decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2)); + assert(r == m.begin() + 2); + assert(m.size() == 5); + assert(*r == 2); + } +} + +template +void test_emplaceable() { + using M = std::flat_set, KeyContainer>; + using R = M::iterator; + + M m; + ASSERT_SAME_TYPE(decltype(m.emplace_hint(m.cbegin())), R); + R r = m.emplace_hint(m.end(), 2, 0.0); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*m.begin() == Emplaceable(2, 0.0)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); + r = m.emplace_hint(m.end(), 1, 3.5); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*m.begin() == Emplaceable(1, 3.5)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>(); + test_emplaceable>>(); + + { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp new file mode 100644 index 00000000000000..386af04d26e9a2 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(iterator position); +// iterator erase(const_iterator position); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(std::next(m.cbegin(), 3)); + assert(m.size() == 7); + assert(i1 == std::next(m.begin(), 3)); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 5); + assert(*std::next(m.begin(), 4) == 6); + assert(*std::next(m.begin(), 5) == 7); + assert(*std::next(m.begin(), 6) == 8); + + std::same_as decltype(auto) i2 = m.erase(std::next(m.begin(), 0)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 5)); + assert(m.size() == 5); + assert(i3 == m.end()); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 3); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + + std::same_as decltype(auto) i4 = m.erase(std::next(m.begin(), 1)); + assert(m.size() == 4); + assert(i4 == std::next(m.begin())); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 6); + assert(*std::next(m.begin(), 3) == 7); + + std::same_as decltype(auto) i5 = m.erase(std::next(m.cbegin(), 2)); + assert(m.size() == 3); + assert(i5 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + assert(*std::next(m.begin(), 2) == 7); + + std::same_as decltype(auto) i6 = m.erase(std::next(m.begin(), 2)); + assert(m.size() == 2); + assert(i6 == std::next(m.begin(), 2)); + assert(*m.begin() == 2); + assert(*std::next(m.begin()) == 5); + + std::same_as decltype(auto) i7 = m.erase(std::next(m.cbegin(), 0)); + assert(m.size() == 1); + assert(i7 == std::next(m.begin(), 0)); + assert(*m.begin() == 5); + + std::same_as decltype(auto) i8 = m.erase(m.begin()); + assert(m.size() == 0); + assert(i8 == m.begin()); + assert(i8 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp new file mode 100644 index 00000000000000..7416977844e5df --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator erase(const_iterator first, const_iterator last); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using I = M::iterator; + + int ar[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + }; + M m(ar, ar + sizeof(ar) / sizeof(ar[0])); + assert(m.size() == 8); + std::same_as decltype(auto) i1 = m.erase(m.cbegin(), m.cbegin()); + assert(m.size() == 8); + assert(i1 == m.begin()); + assert(*m.begin() == 1); + assert(*std::next(m.begin()) == 2); + assert(*std::next(m.begin(), 2) == 3); + assert(*std::next(m.begin(), 3) == 4); + assert(*std::next(m.begin(), 4) == 5); + assert(*std::next(m.begin(), 5) == 6); + assert(*std::next(m.begin(), 6) == 7); + assert(*std::next(m.begin(), 7) == 8); + + std::same_as decltype(auto) i2 = m.erase(m.cbegin(), std::next(m.cbegin(), 2)); + assert(m.size() == 6); + assert(i2 == m.begin()); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + assert(*std::next(m.begin(), 2) == 5); + assert(*std::next(m.begin(), 3) == 6); + assert(*std::next(m.begin(), 4) == 7); + assert(*std::next(m.begin(), 5) == 8); + + std::same_as decltype(auto) i3 = m.erase(std::next(m.cbegin(), 2), std::next(m.cbegin(), 6)); + assert(m.size() == 2); + assert(i3 == std::next(m.begin(), 2)); + assert(*std::next(m.begin(), 0) == 3); + assert(*std::next(m.begin(), 1) == 4); + + std::same_as decltype(auto) i4 = m.erase(m.cbegin(), m.cend()); + assert(m.size() == 0); + assert(i4 == m.begin()); + assert(i4 == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp new file mode 100644 index 00000000000000..25d4f4af19608b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(const key_type& k); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template > +void test() { + using M = std::flat_set; + + auto make = [](std::initializer_list il) { + M m; + for (int i : il) { + m.emplace(i); + } + return m; + }; + M m = make({1, 2, 3, 4, 5, 6, 7, 8}); + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(9); + assert(n == 0); + assert(m == make({1, 2, 3, 4, 5, 6, 7, 8})); + n = m.erase(4); + assert(n == 1); + assert(m == make({1, 2, 3, 5, 6, 7, 8})); + n = m.erase(1); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7, 8})); + n = m.erase(8); + assert(n == 1); + assert(m == make({2, 3, 5, 6, 7})); + n = m.erase(3); + assert(n == 1); + assert(m == make({2, 5, 6, 7})); + n = m.erase(4); + assert(n == 0); + assert(m == make({2, 5, 6, 7})); + n = m.erase(6); + assert(n == 1); + assert(m == make({2, 5, 7})); + n = m.erase(7); + assert(n == 1); + assert(m == make({2, 5})); + n = m.erase(2); + assert(n == 1); + assert(m == make({5})); + n = m.erase(5); + assert(n == 1); + assert(m.empty()); +} + +int main(int, char**) { + test>(); + test, std::greater<>>(); + test>(); + test>(); + test>>(); + + { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp new file mode 100644 index 00000000000000..cbf7cac603806d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type erase(K&& k); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanErase = requires(M m, Transparent k) { m.erase(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanErase); +static_assert(!CanErase); +static_assert(!CanErase); +static_assert(!CanErase); + +template +struct HeterogeneousKey { + explicit HeterogeneousKey(Key key, It it) : key_(key), it_(it) {} + operator It() && { return it_; } + auto operator<=>(Key key) const { return key_ <=> key; } + friend bool operator<(const HeterogeneousKey&, const HeterogeneousKey&) { + assert(false); + return false; + } + Key key_; + It it_; +}; + +template +void test_simple() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = {1, 2, 3, 4}; + ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type); + auto n = m.erase(3); // erase(K&&) [with K=int] + assert(n == 1); + assert((m == M{1, 2, 4})); + typename M::key_type lvalue = 2; + n = m.erase(lvalue); // erase(K&&) [with K=int&] + assert(n == 1); + assert((m == M{1, 4})); + const typename M::key_type const_lvalue = 1; + n = m.erase(const_lvalue); // erase(const key_type&) + assert(n == 1); + assert((m == M{4})); +} + +template +void test_transparent_comparator() { + using M = std::flat_set; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.erase(Transparent{"abc"})), typename M::size_type); + + auto n = m.erase(Transparent{"epsilon"}); + assert(n == 1); + + M expected = {"alpha", "beta", "eta", "gamma"}; + assert(m == expected); + + auto n2 = m.erase(Transparent{"aaa"}); + assert(n2 == 0); + assert(m == expected); +} + +int main(int, char**) { + test_simple>(); + test_simple>(); + test_simple>(); + test_simple>>(); + + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>(); + test_transparent_comparator>>(); + + { + // P2077's HeterogeneousKey example + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + using M = std::flat_set>; + M m = {1, 2, 3, 4, 5, 6, 7, 8}; + auto h1 = HeterogeneousKey(8, m.begin()); + std::same_as auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match + assert(n == 1); + assert((m == M{1, 2, 3, 4, 5, 6, 7})); + std::same_as auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out + assert(it == m.begin()); + assert((m == M{2, 3, 4, 5, 6, 7})); + } + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.erase(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp new file mode 100644 index 00000000000000..c3bbffabb90a08 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// containers extract() &&; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanExtract = requires(T&& t) { std::forward(t).extract(); }; + +static_assert(CanExtract&&>); +static_assert(!CanExtract&>); +static_assert(!CanExtract const&>); +static_assert(!CanExtract const&&>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + M m = M({1, 2, 3}); + + std::same_as auto keys = std::move(m).extract(); + + auto expected_keys = {1, 2, 3}; + assert(std::ranges::equal(keys, expected_keys)); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // extracted object maintains invariant if the underlying container does not clear after move + using M = std::flat_set, CopyOnlyVector>; + M m = M({1, 2, 3}); + std::same_as auto keys = std::move(m).extract(); + assert(keys.size() == 3); + check_invariant(m); + LIBCPP_ASSERT(m.empty()); + } + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + auto c = std::move(m).extract(); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we try to erase the key after value emplacement failure. + // and after erasure failure, we clear the flat_set + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp new file mode 100644 index 00000000000000..c0ddadc3006987 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair insert(const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using VT = typename M::value_type; + M m; + + const VT v1(2); + std::same_as decltype(auto) r = m.insert(v1); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == 2); + + const VT v2(1); + r = m.insert(v2); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == 1); + + const VT v3(3); + r = m.insert(v3); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); + + const VT v4(3); + r = m.insert(v4); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp new file mode 100644 index 00000000000000..7381514a70eabb --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; + + M m = {1,1,1,3,3,3}; + m.insert({ + 4, + 4, + 4, + 1, + 1, + 1, + 2, + 2, + 2, + }); + assert(m.size() == 4); + assert(std::distance(m.begin(), m.end()) == 4); + assert(*m.begin() == V(1)); + assert(*std::next(m.begin()) == V(2)); + assert(*std::next(m.begin(), 2) == V(3)); + assert(*std::next(m.begin(), 3) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp new file mode 100644 index 00000000000000..c343d53a62215a --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator insert(const_iterator position, const value_type& v); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "../helpers.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using R = typename M::iterator; + using VT = typename M::value_type; + + M m; + const VT v1(2); + std::same_as decltype(auto) r = m.insert(m.end(), v1); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == 2); + + const VT v2(1); + r = m.insert(m.end(), v2); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == 1); + + const VT v3(3); + r = m.insert(m.end(), v3); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); + + const VT v4(3); + r = m.insert(m.end(), v4); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == 3); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp new file mode 100644 index 00000000000000..d20a8ef8fdd92d --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using M = std::flat_set, KeyContainer>; + + int ar1[] = { + 2, + 2, + 2, + 1, + 1, + 1, + 3, + 3, + 3, + }; + int ar2[] = { + 4, + 4, + 4, + 1, + 1, + 1, + 0, + 0, + 0, + }; + + M m; + m.insert(cpp17_input_iterator(ar1), cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(cpp17_input_iterator(ar2), cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp new file mode 100644 index 00000000000000..84b6c7fc1d34f6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// +// iterator insert(const_iterator position, value_type&&); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "../helpers.h" +#include "test_macros.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + using R = typename M::iterator; + M m; + std::same_as decltype(auto) r = m.insert(m.end(), V(2)); + assert(r == m.begin()); + assert(m.size() == 1); + assert(*r == V(2)); + + r = m.insert(m.end(), V(1)); + assert(r == m.begin()); + assert(m.size() == 2); + assert(*r == V(1)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); + + r = m.insert(m.end(), V(3)); + assert(r == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp new file mode 100644 index 00000000000000..536307252c6405 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template R> +// void insert_range(R&& rg); + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "MoveOnly.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint container-compatible-range +template +concept CanInsertRange = requires(M m, R&& r) { m.insert_range(std::forward(r)); }; + +using Set = std::flat_set; + +static_assert(CanInsertRange>); +static_assert(CanInsertRange>); +static_assert(!CanInsertRange*>>); +static_assert(!CanInsertRange*>>); + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using M = std::flat_set, KeyContainer>; + using It = forward_iterator; + M m = {10, 8, 5, 2, 1}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), It(ar + 6)}; + static_assert(std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9, 10})); + } + { + using M = std::flat_set, KeyContainer>; + using It = cpp20_input_iterator; + M m = {8, 5, 3, 2}; + int ar[] = {3, 1, 4, 1, 5, 9}; + std::ranges::subrange r = {It(ar), sentinel_wrapper(It(ar + 6))}; + static_assert(!std::ranges::common_range); + m.insert_range(r); + assert((m == M{1, 2, 3, 4, 5, 8, 9})); + } + { + // The "uniquing" part uses the comparator, not operator==. + struct ModTen { + bool operator()(int a, int b) const { return (a % 10) < (b % 10); } + }; + using M = std::flat_set; + M m = {21, 43, 15, 37}; + int ar[] = {33, 18, 55, 18, 42}; + m.insert_range(ar); + assert((m == M{21, 42, 43, 15, 37, 18})); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + // Items are forwarded correctly from the input range (P2767). + MoveOnly a[] = {3, 1, 4, 1, 5}; + std::flat_set m; + m.insert_range(a | std::views::as_rvalue); + MoveOnly expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + // The element type of the range doesn't need to be std::pair (P2767). + int pa[] = {3, 1, 4, 1, 5}; + std::deque> a(pa, pa + 5); + std::flat_set m; + m.insert_range(a); + int expected[] = {1, 3, 4, 5}; + assert(std::ranges::equal(m, expected)); + } + { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp new file mode 100644 index 00000000000000..7d95f0521eb1f6 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set + +// pair insert( value_type&& v); + +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + using R = std::pair; + using V = typename M::value_type; + + M m; + std::same_as decltype(auto) r = m.insert(V(2)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 1); + assert(*r.first == V(2)); + + r = m.insert(V(1)); + assert(r.second); + assert(r.first == m.begin()); + assert(m.size() == 2); + assert(*r.first == V(1)); + + r = m.insert(V(3)); + assert(r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); + + r = m.insert(V(3)); + assert(!r.second); + assert(r.first == std::ranges::prev(m.end())); + assert(m.size() == 3); + assert(*r.first == V(3)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test>>(); + test>>(); + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp new file mode 100644 index 00000000000000..fa5bf86830daec --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void insert(sorted_unique_t, initializer_list il); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = Key; + M m = {1, 1, 1, 3, 3, 3}; + m.insert(std::sorted_unique, {0, 1, 2, 4}); + assert(m.size() == 5); + assert(std::distance(m.begin(), m.end()) == 5); + assert(*m.begin() == V(0)); + assert(*std::next(m.begin()) == V(1)); + assert(*std::next(m.begin(), 2) == V(2)); + assert(*std::next(m.begin(), 3) == V(3)); + assert(*std::next(m.begin(), 4) == V(4)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp new file mode 100644 index 00000000000000..ef7b8391cee33c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template +// void insert(sorted_unique_t, InputIterator first, InputIterator last); + +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// test constraint InputIterator +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; + +static_assert(CanInsert); +static_assert(CanInsert, cpp17_input_iterator>); +static_assert(!CanInsert); +static_assert(!CanInsert, cpp20_input_iterator>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + int ar1[] = {1, 2, 3}; + + int ar2[] = {0, 2, 4}; + + M m; + m.insert(std::sorted_unique, + cpp17_input_iterator(ar1), + cpp17_input_iterator(ar1 + sizeof(ar1) / sizeof(ar1[0]))); + assert(m.size() == 3); + M expected{1, 2, 3}; + assert(m == expected); + + m.insert(std::sorted_unique, + cpp17_input_iterator(ar2), + cpp17_input_iterator(ar2 + sizeof(ar2) / sizeof(ar2[0]))); + assert(m.size() == 5); + M expected2{0, 1, 2, 3, 4}; + assert(m == expected2); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp new file mode 100644 index 00000000000000..72d7261a182547 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -0,0 +1,169 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair insert(P&& x); +// template iterator insert(const_iterator hint, P&& x); + +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +// Constraints: is_constructible_v is true. +template +concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; + +using Set = std::flat_set; +using Iter = Set::const_iterator; + +static_assert(CanInsert); +static_assert(CanInsert); +static_assert(!CanInsert); +static_assert(!CanInsert); + +static int expensive_comparisons = 0; +static int cheap_comparisons = 0; + +struct CompareCounter { + int i_ = 0; + CompareCounter(int i) : i_(i) {} + friend auto operator<=>(const CompareCounter& x, const CompareCounter& y) { + expensive_comparisons += 1; + return x.i_ <=> y.i_; + } + bool operator==(const CompareCounter&) const = default; + friend auto operator<=>(const CompareCounter& x, int y) { + cheap_comparisons += 1; + return x.i_ <=> y; + } +}; + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + const int expected[] = {1, 2, 3, 4, 5}; + { + // insert(P&&) + // Unlike flat_set, here we can't use key_compare to compare value_type versus P, + // so we must eagerly convert to value_type. + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, P&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // insert(value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.insert(3); // conversion happens last + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, value_type&&) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as auto it = m.insert(m.begin(), 3); + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } + { + // emplace(Args&&...) + M m = {1, 2, 4, 5}; + expensive_comparisons = 0; + cheap_comparisons = 0; + std::same_as> auto p = m.emplace(3); // conversion happens first + assert(expensive_comparisons >= 2); + assert(cheap_comparisons == 0); + assert(p == std::make_pair(m.begin() + 2, true)); + assert(std::ranges::equal(m, expected)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + // no ambiguity between insert(pos, P&&) and insert(first, last) + using M = std::flat_set; + struct Evil { + operator M::value_type() const; + operator M::const_iterator() const; + }; + std::flat_set m; + ASSERT_SAME_TYPE(decltype(m.insert(Evil())), std::pair); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); + ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); + } + { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(t); + }; + test_emplace_exception_guarantee(insert_func); + } + { + auto insert_func_iter = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + struct T { + typename FlatSet::key_type key; + T(typename FlatSet::key_type key) : key(key) {} + operator typename FlatSet::value_type() const { return key; } + }; + T t(key_arg); + m.insert(m.begin(), t); + }; + test_emplace_exception_guarantee(insert_func_iter); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp new file mode 100644 index 00000000000000..49cb6eb6163c90 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void replace(container_type&& key_cont); + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +concept CanReplace = requires(T t, Args&&... args) { t.replace(std::forward(args)...); }; + +using Set = std::flat_set; +static_assert(CanReplace>); +static_assert(!CanReplace&>); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + M m = M({1, 2, 3}); + KeyContainer new_keys = {7, 8}; + auto expected_keys = new_keys; + m.replace(std::move(new_keys)); + assert(m.size() == 2); + assert(std::ranges::equal(m, expected_keys)); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); + } +#endif + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp new file mode 100644 index 00000000000000..23a2dc85989bb7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// `check_assertion.h` requires Unix headers and regex support. +// REQUIRES: has-unix-headers +// UNSUPPORTED: no-localization +// UNSUPPORTED: no-exceptions + +// + +// void swap(flat_set& y) noexcept; +// friend void swap(flat_set& x, flat_set& y) noexcept + +// Test that std::terminate is called if any exception is thrown during swap + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "../helpers.h" +#include "check_assertion.h" + +template +void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) { + { + // key swap throws + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; + + M m1, m2; + m1.emplace(1); + m1.emplace(2); + m2.emplace(3); + m2.emplace(4); + // swap is noexcept + EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); }); + } +} + +int main(int, char**) { + { + auto swap_func = [](auto& m1, auto& m2) { swap(m1, m2); }; + test_swap_exception_guarantee(swap_func); + } + + { + auto swap_func = [](auto& m1, auto& m2) { m1.swap(m2); }; + test_swap_exception_guarantee(swap_func); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp new file mode 100644 index 00000000000000..bc7baa67e52a59 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend void swap(flat_set& x, flat_set& y) noexcept + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptAdlSwap = requires(T t1, T t2) { + { swap(t1, t2) } noexcept; +}; + +static_assert(NoExceptAdlSwap>); + +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptAdlSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + swap(m1, m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp new file mode 100644 index 00000000000000..b0b06a9499efc7 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void swap(flat_set& y) noexcept; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "MoveOnly.h" +#include "min_allocator.h" +#include "test_macros.h" +#include "../helpers.h" + +// test noexcept + +template +concept NoExceptMemberSwap = requires(T t1, T t2) { + { t1.swap(t2) } noexcept; +}; + +static_assert(NoExceptMemberSwap>); +#ifndef TEST_HAS_NO_EXCEPTIONS +static_assert(NoExceptMemberSwap, ThrowOnMoveContainer>>); +#endif + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + { + M m1; + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1; + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2; + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } + { + int ar1[] = {1, 2, 3, 4}; + int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12}; + M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0])); + M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0])); + M m1_save = m1; + M m2_save = m2; + m1.swap(m2); + assert(m1 == m2_save); + assert(m2 == m1_save); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp new file mode 100644 index 00000000000000..971b5e1c338dd1 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// key_compare key_comp() const; +// value_compare value_comp() const; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + { + using M = std::flat_set; + using Comp = std::less; // the default + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + { + using Comp = std::function; + using M = std::flat_set; + Comp comp = std::greater(); + M m({}, comp); + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(!kc(1, 2)); + assert(kc(2, 1)); + auto vc = m.value_comp(); + assert(!vc(1, 2)); + assert(vc(2, 1)); + } + { + using Comp = std::less<>; + using M = std::flat_set; + M m = {}; + ASSERT_SAME_TYPE(M::key_compare, Comp); + ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp); + ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp); + Comp kc = m.key_comp(); + assert(kc(1, 2)); + assert(!kc(2, 1)); + auto vc = m.value_comp(); + auto a = std::make_pair(1, 2); + ASSERT_SAME_TYPE(decltype(vc(a, a)), bool); + assert(vc(1, 2)); + assert(!vc(2, 1)); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp new file mode 100644 index 00000000000000..b14da66f611301 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// bool contains(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + assert(!m.contains(0)); + assert(m.contains(1)); + assert(m.contains(2)); + assert(!m.contains(3)); + assert(m.contains(4)); + assert(m.contains(5)); + assert(!m.contains(6)); + assert(!m.contains(7)); + assert(std::as_const(m).contains(8)); + assert(!std::as_const(m).contains(9)); + m.clear(); + assert(!m.contains(1)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp new file mode 100644 index 00000000000000..507560608952b0 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template bool contains(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanContains = requires(M m, Transparent k) { m.contains(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanContains); +static_assert(CanContains); +static_assert(!CanContains); +static_assert(!CanContains); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.contains(Transparent{"abc"})), bool); + ASSERT_SAME_TYPE(decltype(std::as_const(m).contains(Transparent{"b"})), bool); + assert(m.contains(Transparent{"alpha"}) == true); + assert(m.contains(Transparent{"beta"}) == true); + assert(m.contains(Transparent{"epsilon"}) == true); + assert(m.contains(Transparent{"eta"}) == true); + assert(m.contains(Transparent{"gamma"}) == true); + assert(m.contains(Transparent{"al"}) == false); + assert(m.contains(Transparent{""}) == false); + assert(m.contains(Transparent{"g"}) == false); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto b = m.contains(Transparent{3}); + assert(b); + assert(transparent_used); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp new file mode 100644 index 00000000000000..478f615358b606 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// size_type count(const key_type& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using S = typename KeyContainer::size_type; + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.count(0)), S); + assert(m.count(0) == 0); + assert(m.count(1) == 1); + assert(m.count(2) == 1); + assert(m.count(3) == 0); + assert(m.count(4) == 1); + assert(m.count(5) == 1); + assert(m.count(6) == 0); + assert(m.count(7) == 0); + assert(std::as_const(m).count(8) == 1); + assert(std::as_const(m).count(9) == 0); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp new file mode 100644 index 00000000000000..b591258f74399c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template size_type count(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanCount = requires(M m, Transparent k) { m.count(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanCount); +static_assert(CanCount); +static_assert(!CanCount); +static_assert(!CanCount); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + ASSERT_SAME_TYPE(decltype(m.count(Transparent{"abc"})), typename M::size_type); + ASSERT_SAME_TYPE(decltype(std::as_const(m).count(Transparent{"b"})), typename M::size_type); + assert(m.count(Transparent{"alpha"}) == 1); + assert(m.count(Transparent{"beta"}) == 1); + assert(m.count(Transparent{"epsilon"}) == 1); + assert(m.count(Transparent{"eta"}) == 1); + assert(m.count(Transparent{"gamma"}) == 1); + assert(m.count(Transparent{"al"}) == 0); + assert(m.count(Transparent{""}) == 0); + assert(m.count(Transparent{"g"}) == 0); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto n = m.count(Transparent{3}); + assert(n == 1); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp new file mode 100644 index 00000000000000..a088b7fee17d2c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// pair equal_range(const key_type& k); +// pair equal_range(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin, begin)); + assert(m.equal_range(1) == std::pair(begin, begin + 1)); + assert(m.equal_range(2) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(3) == std::pair(begin + 2, begin + 2)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(6) == std::pair(begin + 4, begin + 4)); + assert(m.equal_range(7) == std::pair(begin + 4, begin + 4)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin() + 4, m.cbegin() + 5)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin() + 5, m.cbegin() + 5)); + } + + { + using M = std::flat_set, KeyContainer>; + using R = std::pair; + using CR = std::pair; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR); + auto begin = m.begin(); + assert(m.equal_range(0) == std::pair(begin + 5, begin + 5)); + assert(m.equal_range(1) == std::pair(begin + 4, begin + 5)); + assert(m.equal_range(2) == std::pair(begin + 3, begin + 4)); + assert(m.equal_range(3) == std::pair(begin + 3, begin + 3)); + assert(m.equal_range(4) == std::pair(begin + 2, begin + 3)); + assert(m.equal_range(5) == std::pair(begin + 1, begin + 2)); + assert(m.equal_range(6) == std::pair(begin + 1, begin + 1)); + assert(m.equal_range(7) == std::pair(begin + 1, begin + 1)); + assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin(), m.cbegin() + 1)); + assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin(), m.cbegin())); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp new file mode 100644 index 00000000000000..ede5d91e19b9fd --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template pair equal_range(const K& x); +// template pair equal_range(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanEqualRange = requires(M m, Transparent k) { m.equal_range(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanEqualRange); +static_assert(CanEqualRange); +static_assert(!CanEqualRange); +static_assert(!CanEqualRange); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + using R = std::pair; + using CR = std::pair; + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.equal_range(Transparent{"abc"})), R); + ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(Transparent{"b"})), CR); + + auto test_found = [&](auto&& map, const std::string& expected_key) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(last - first == 1); + assert(*first == expected_key); + }; + + auto test_not_found = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto [first, last] = map.equal_range(Transparent{expected_key}); + assert(first == last); + assert(first - m.begin() == expected_offset); + }; + + test_found(m, "alpha"); + test_found(m, "beta"); + test_found(m, "epsilon"); + test_found(m, "eta"); + test_found(m, "gamma"); + test_found(cm, "alpha"); + test_found(cm, "beta"); + test_found(cm, "epsilon"); + test_found(cm, "eta"); + test_found(cm, "gamma"); + + test_not_found(m, "charlie", 2); + test_not_found(m, "aaa", 0); + test_not_found(m, "zzz", 5); + test_not_found(cm, "charlie", 2); + test_not_found(cm, "aaa", 0); + test_not_found(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto p = m.equal_range(Transparent{3}); + assert(p.first != p.second); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp new file mode 100644 index 00000000000000..cf0dd2d1dd831c --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator find(const key_type& k); +// const_iterator find(const key_type& k) const; + +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.find(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(0)), typename M::const_iterator); + assert(m.find(0) == m.end()); + assert(m.find(1) == m.begin()); + assert(m.find(2) == m.begin() + 1); + assert(m.find(3) == m.end()); + assert(m.find(4) == m.begin() + 2); + assert(m.find(5) == m.begin() + 3); + assert(m.find(6) == m.end()); + assert(m.find(7) == m.end()); + assert(std::as_const(m).find(8) == m.begin() + 4); + assert(std::as_const(m).find(9) == m.end()); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp new file mode 100644 index 00000000000000..730a57b0a6cb85 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator find(const K& x); +// template const_iterator find(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanFind = requires(M m, Transparent k) { m.find(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanFind); +static_assert(CanFind); +static_assert(!CanFind); +static_assert(!CanFind); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.find(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).find(Transparent{"b"})), typename M::const_iterator); + + auto test_find = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.find(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_find(m, "alpha", 0); + test_find(m, "beta", 1); + test_find(m, "epsilon", 2); + test_find(m, "eta", 3); + test_find(m, "gamma", 4); + test_find(m, "charlie", 5); + test_find(m, "aaa", 5); + test_find(m, "zzz", 5); + test_find(cm, "alpha", 0); + test_find(cm, "beta", 1); + test_find(cm, "epsilon", 2); + test_find(cm, "eta", 3); + test_find(cm, "gamma", 4); + test_find(cm, "charlie", 5); + test_find(cm, "aaa", 5); + test_find(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.find(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp new file mode 100644 index 00000000000000..093c32e537ed35 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator lower_bound(const key_type& k); +// const_iterator lower_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.begin()); + assert(m.lower_bound(1) == m.begin()); + assert(m.lower_bound(2) == m.begin() + 1); + assert(m.lower_bound(3) == m.begin() + 2); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 3); + assert(m.lower_bound(6) == m.begin() + 4); + assert(m.lower_bound(7) == m.begin() + 4); + assert(std::as_const(m).lower_bound(8) == m.begin() + 4); + assert(std::as_const(m).lower_bound(9) == m.end()); + } + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator); + assert(m.lower_bound(0) == m.end()); + assert(m.lower_bound(1) == m.begin() + 4); + assert(m.lower_bound(2) == m.begin() + 3); + assert(m.lower_bound(3) == m.begin() + 3); + assert(m.lower_bound(4) == m.begin() + 2); + assert(m.lower_bound(5) == m.begin() + 1); + assert(m.lower_bound(6) == m.begin() + 1); + assert(m.lower_bound(7) == m.begin() + 1); + assert(std::as_const(m).lower_bound(8) == m.begin()); + assert(std::as_const(m).lower_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp new file mode 100644 index 00000000000000..18f9bc6dd32955 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator lower_bound(const K& x); +// template const_iterator lower_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanLowerBound = requires(M m, Transparent k) { m.lower_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanLowerBound); +static_assert(CanLowerBound); +static_assert(!CanLowerBound); +static_assert(!CanLowerBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_lower_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.lower_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_lower_bound(m, "abc", 0); + test_lower_bound(m, "alpha", 0); + test_lower_bound(m, "beta", 1); + test_lower_bound(m, "bets", 2); + test_lower_bound(m, "charlie", 2); + test_lower_bound(m, "echo", 2); + test_lower_bound(m, "epsilon", 2); + test_lower_bound(m, "eta", 3); + test_lower_bound(m, "gamma", 4); + test_lower_bound(m, "golf", 5); + test_lower_bound(m, "zzz", 5); + + test_lower_bound(cm, "abc", 0); + test_lower_bound(cm, "alpha", 0); + test_lower_bound(cm, "beta", 1); + test_lower_bound(cm, "bets", 2); + test_lower_bound(cm, "charlie", 2); + test_lower_bound(cm, "echo", 2); + test_lower_bound(cm, "epsilon", 2); + test_lower_bound(cm, "eta", 3); + test_lower_bound(cm, "gamma", 4); + test_lower_bound(cm, "golf", 5); + test_lower_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.lower_bound(Transparent{3}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp new file mode 100644 index 00000000000000..ab34de85103175 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// iterator upper_bound(const key_type& k); +// const_iterator upper_bound(const key_type& k) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.begin()); + assert(m.upper_bound(1) == m.begin() + 1); + assert(m.upper_bound(2) == m.begin() + 2); + assert(m.upper_bound(3) == m.begin() + 2); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 4); + assert(m.upper_bound(6) == m.begin() + 4); + assert(std::as_const(m).upper_bound(7) == m.begin() + 4); + assert(std::as_const(m).upper_bound(8) == m.end()); + assert(std::as_const(m).upper_bound(9) == m.end()); + } + + { + using M = std::flat_set, KeyContainer>; + M m = {1, 2, 4, 5, 8}; + ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator); + assert(m.upper_bound(0) == m.end()); + assert(m.upper_bound(1) == m.end()); + assert(m.upper_bound(2) == m.begin() + 4); + assert(m.upper_bound(3) == m.begin() + 3); + assert(m.upper_bound(4) == m.begin() + 3); + assert(m.upper_bound(5) == m.begin() + 2); + assert(m.upper_bound(6) == m.begin() + 1); + assert(m.upper_bound(7) == m.begin() + 1); + assert(std::as_const(m).upper_bound(8) == m.begin() + 1); + assert(std::as_const(m).upper_bound(9) == m.begin()); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp new file mode 100644 index 00000000000000..69ce2ae926a305 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template iterator upper_bound(const K& x); +// template const_iterator upper_bound(const K& x) const; + +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "../helpers.h" +#include "test_macros.h" +#include "min_allocator.h" + +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. +template +concept CanUpperBound = requires(M m, Transparent k) { m.upper_bound(k); }; +using TransparentSet = std::flat_set; +using NonTransparentSet = std::flat_set; +static_assert(CanUpperBound); +static_assert(CanUpperBound); +static_assert(!CanUpperBound); +static_assert(!CanUpperBound); + +template +void test() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set; + + M m = {"alpha", "beta", "epsilon", "eta", "gamma"}; + const auto& cm = m; + ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent{"abc"})), typename M::iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent{"b"})), typename M::const_iterator); + + auto test_upper_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) { + auto iter = map.upper_bound(Transparent{expected_key}); + assert(iter - map.begin() == expected_offset); + }; + + test_upper_bound(m, "abc", 0); + test_upper_bound(m, "alpha", 1); + test_upper_bound(m, "beta", 2); + test_upper_bound(m, "bets", 2); + test_upper_bound(m, "charlie", 2); + test_upper_bound(m, "echo", 2); + test_upper_bound(m, "epsilon", 3); + test_upper_bound(m, "eta", 4); + test_upper_bound(m, "gamma", 5); + test_upper_bound(m, "golf", 5); + test_upper_bound(m, "zzz", 5); + + test_upper_bound(cm, "abc", 0); + test_upper_bound(cm, "alpha", 1); + test_upper_bound(cm, "beta", 2); + test_upper_bound(cm, "bets", 2); + test_upper_bound(cm, "charlie", 2); + test_upper_bound(cm, "echo", 2); + test_upper_bound(cm, "epsilon", 3); + test_upper_bound(cm, "eta", 4); + test_upper_bound(cm, "gamma", 5); + test_upper_bound(cm, "golf", 5); + test_upper_bound(cm, "zzz", 5); +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + { + bool transparent_used = false; + TransparentComparator c(transparent_used); + std::flat_set m(std::sorted_unique, {1, 2, 3}, c); + assert(!transparent_used); + auto it = m.upper_bound(Transparent{2}); + assert(it != m.end()); + assert(transparent_used); + } + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h new file mode 100644 index 00000000000000..9fff262d84234e --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -0,0 +1,294 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_flat_set_HELPERS_H +#define SUPPORT_flat_set_HELPERS_H + +#include +#include +#include +#include +#include + +#include "test_allocator.h" +#include "test_macros.h" + +template +void check_invariant(const std::flat_set& m) { + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); + auto key_equal = [&](const auto& x, const auto& y) { + const auto& c = m.key_comp(); + return !c(x, y) && !c(y, x); + }; + assert(std::adjacent_find(m.begin(), m.end(), key_equal) == m.end()); +} + +struct StartsWith { + explicit StartsWith(char ch) : lower_(1, ch), upper_(1, ch + 1) {} + StartsWith(const StartsWith&) = delete; + void operator=(const StartsWith&) = delete; + struct Less { + using is_transparent = void; + bool operator()(const std::string& a, const std::string& b) const { return a < b; } + bool operator()(const StartsWith& a, const std::string& b) const { return a.upper_ <= b; } + bool operator()(const std::string& a, const StartsWith& b) const { return a < b.lower_; } + bool operator()(const StartsWith&, const StartsWith&) const { + assert(false); // should not be called + return false; + } + }; + +private: + std::string lower_; + std::string upper_; +}; + +template +struct CopyOnlyVector : std::vector { + using std::vector::vector; + + CopyOnlyVector(const CopyOnlyVector&) = default; + CopyOnlyVector(CopyOnlyVector&& other) : CopyOnlyVector(other) {} + CopyOnlyVector(CopyOnlyVector&& other, std::vector::allocator_type alloc) : CopyOnlyVector(other, alloc) {} + + CopyOnlyVector& operator=(const CopyOnlyVector&) = default; + CopyOnlyVector& operator=(CopyOnlyVector& other) { return this->operator=(other); } +}; + +template +struct Transparent { + T t; + + operator T() const + requires ConvertibleToT + { + return t; + } +}; + +template +using ConvertibleTransparent = Transparent; + +template +using NonConvertibleTransparent = Transparent; + +struct TransparentComparator { + using is_transparent = void; + + bool* transparent_used = nullptr; + TransparentComparator() = default; + TransparentComparator(bool& used) : transparent_used(&used) {} + + template + bool operator()(const T& t, const Transparent& transparent) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return t < transparent.t; + } + + template + bool operator()(const Transparent& transparent, const T& t) const { + if (transparent_used != nullptr) { + *transparent_used = true; + } + return transparent.t < t; + } + + template + bool operator()(const T& t1, const T& t2) const { + return t1 < t2; + } +}; + +struct NonTransparentComparator { + template + bool operator()(const T&, const Transparent&) const; + + template + bool operator()(const Transparent&, const T&) const; + + template + bool operator()(const T&, const T&) const; +}; + +struct NoDefaultCtr { + NoDefaultCtr() = delete; +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +struct EmplaceUnsafeContainer : std::vector { + using std::vector::vector; + + template + auto emplace(Args&&... args) -> decltype(std::declval>().emplace(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } + + template + auto insert(Args&&... args) -> decltype(std::declval>().insert(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } +}; + +template +struct ThrowOnEraseContainer : std::vector { + using std::vector::vector; + + template + auto erase(Args&&... args) -> decltype(std::declval>().erase(std::forward(args)...)) { + throw 42; + } +}; + +template +struct ThrowOnMoveContainer : std::vector { + using std::vector::vector; + + ThrowOnMoveContainer(ThrowOnMoveContainer&&) { throw 42; } + + ThrowOnMoveContainer& operator=(ThrowOnMoveContainer&&) { throw 42; } +}; + +#endif + +template +void test_emplace_exception_guarantee([[maybe_unused]] F&& emplace_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using C = TransparentComparator; + { + // Throw on emplace the key, and underlying has strong exception guarantee + using KeyContainer = std::vector>; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + + test_allocator_statistics stats; + + KeyContainer a({1, 2, 3, 4}, test_allocator{&stats}); + [[maybe_unused]] auto expected_keys = a; + M m(std::sorted_unique, std::move(a)); + + stats.throw_after = 1; + try { + emplace_function(m, 0); + assert(false); + } catch (const std::bad_alloc&) { + check_invariant(m); + // In libc++, the flat_set is unchanged + LIBCPP_ASSERT(m.size() == 4); + LIBCPP_ASSERT(std::ranges::equal(m, expected_keys)); + } + } + { + // Throw on emplace the key, and underlying has no strong exception guarantee + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + + LIBCPP_STATIC_ASSERT(!std::__container_traits::__emplacement_has_strong_exception_safety_guarantee); + KeyContainer a = {1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + emplace_function(m, 0); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, the flat_set is cleared + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} + +template +void test_insert_range_exception_guarantee([[maybe_unused]] F&& insert_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + using KeyContainer = EmplaceUnsafeContainer; + using M = std::flat_set; + test_allocator_statistics stats; + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + + std::vector newValues = {0, 1, 5, 6, 7, 8}; + stats.throw_after = 1; + try { + insert_function(m, newValues); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when inserting a range + LIBCPP_ASSERT(m.size() == 0); + } +#endif +} + +template +void test_erase_exception_guarantee([[maybe_unused]] F&& erase_function) { +#ifndef TEST_HAS_NO_EXCEPTIONS + { + // key erase throws + using KeyContainer = ThrowOnEraseContainer; + using M = std::flat_set; + + KeyContainer a{1, 2, 3, 4}; + M m(std::sorted_unique, std::move(a)); + try { + erase_function(m, 3); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear if anything goes wrong when erasing + LIBCPP_ASSERT(m.size() == 0); + } + } +#endif +} +class Moveable { + int int_; + double double_; + +public: + Moveable() : int_(0), double_(0) {} + Moveable(int i, double d) : int_(i), double_(d) {} + Moveable(Moveable&& x) : int_(x.int_), double_(x.double_) { + x.int_ = -1; + x.double_ = -1; + } + Moveable& operator=(Moveable&& x) { + int_ = x.int_; + x.int_ = -1; + double_ = x.double_; + x.double_ = -1; + return *this; + } + + Moveable(const Moveable&) = delete; + Moveable& operator=(const Moveable&) = delete; + bool operator==(const Moveable& x) const { return int_ == x.int_ && double_ == x.double_; } + bool operator<(const Moveable& x) const { return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_); } + + int get() const { return int_; } + bool moved() const { return int_ == -1; } +}; + +#endif // SUPPORT_flat_set_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp new file mode 100644 index 00000000000000..c4a9810016536b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// Check that std::flat_set and its iterators can be instantiated with an incomplete +// type. + +#include +#include + +struct A { + using Set = std::flat_set; + int data; + Set m; + Set::iterator it; + Set::const_iterator cit; +}; + +// Implement the operator< required in order to instantiate flat_set +bool operator<(A const& L, A const& R) { return L.data < R.data; } + +int main(int, char**) { + A a; + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp new file mode 100644 index 00000000000000..f6d08bb736d300 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// friend bool operator==(const flat_set& x, const flat_set& y); +// friend synth-three-way-result +// operator<=>(const flat_set& x, const flat_set& y); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MinSequenceContainer.h" +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_comparisons.h" +#include "test_container_comparisons.h" + +template +void test() { + using Key = typename KeyContainer::value_type; + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, true)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } + { + // Comparisons use value_type's native operators, not the comparator + using C = std::flat_set>; + C s1 = {1}; + C s2 = {2}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering); + AssertComparisonsReturnBool(); + assert(testComparisons(s1, s2, false, true)); + s2 = {1}; + assert(testComparisons(s1, s2, true, false)); + s2 = {1, 2}; + assert(testComparisons(s1, s2, false, true)); + s1 = {0, 1, 2}; + assert(testComparisons(s1, s2, false, false)); + s2 = {0, 1, 3}; + assert(testComparisons(s1, s2, false, true)); + } +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>>(); + + { + using C = std::flat_set; + C s1 = {1}; + C s2 = C(std::sorted_unique, {std::numeric_limits::quiet_NaN()}); + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + } + { + // Comparisons use value_type's native operators, not the comparator + struct StrongComp { + bool operator()(double a, double b) const { return std::strong_order(a, b) < 0; } + }; + using C = std::flat_set; + C s1 = {1}; + C s2 = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering); + AssertComparisonsReturnBool(); + assert(testComparisonsComplete(s1, s2, false, false, false)); + s1 = {1, std::numeric_limits::quiet_NaN(), 1}; + s2 = {std::numeric_limits::quiet_NaN(), 1}; + assert(std::lexicographical_compare_three_way(s1.begin(), s1.end(), s2.begin(), s2.end(), std::strong_order) == + std::strong_ordering::equal); + assert(s1 != s2); + assert((s1 <=> s2) == std::partial_ordering::unordered); + } + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp new file mode 100644 index 00000000000000..a845b2b81e89d3 --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.set/types.compile.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// using key_type = Key; +// using value_type = Key; +// using key_compare = Compare; +// using value_compare = Compare; +// using reference = value_type&; +// using const_reference = const value_type&; +// using size_type = typename KeyContainer::size_type; +// using difference_type = typename KeyContainer::difference_type; +// using iterator = implementation-defined; // see [container.requirements] +// using const_iterator = implementation-defined; // see [container.requirements] +// using reverse_iterator = std::reverse_iterator; +// using const_reverse_iterator = std::reverse_iterator; +// using container_type = KeyContainer; + +#include +#include +#include +#include +#include +#include +#include +#include "min_allocator.h" + +void test() { + { + using M = std::flat_set; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(requires { typename M::value_compare; }); + } + + { + struct A {}; + struct Compare { + bool operator()(const std::string&, const std::string&) const; + }; + using M = std::flat_set>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(requires { typename M::iterator; }); + static_assert(requires { typename M::const_iterator; }); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + static_assert(std::is_same_v>); + } + { + using C = std::flat_set, std::deque>>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + // size_type is invariably size_t + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>>); + } +} >From 96903d9c8f1ea42de65fbe1a07e59413a1630d1e Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 13:21:24 +0000 Subject: [PATCH 2/9] review --- libcxx/include/__flat_set/flat_set.h | 137 +++---- .../flat.set/flat.set.capacity/empty.pass.cpp | 14 +- .../flat.set.capacity/max_size.pass.cpp | 8 +- .../flat.set/flat.set.capacity/size.pass.cpp | 14 +- .../flat.set/flat.set.cons/alloc.pass.cpp | 6 +- .../assign_initializer_list.pass.cpp | 19 +- .../flat.set/flat.set.cons/compare.pass.cpp | 6 +- .../flat.set.cons/containers.pass.cpp | 25 +- .../flat.set/flat.set.cons/copy.pass.cpp | 6 +- .../flat.set.cons/copy_alloc.pass.cpp | 6 +- .../copy_assign.addressof.compile.pass.cpp | 30 -- .../flat.set.cons/copy_assign.pass.cpp | 17 +- .../flat.set/flat.set.cons/deduct.pass.cpp | 353 +++++++++--------- .../flat.set/flat.set.cons/default.pass.cpp | 36 +- .../flat.set.cons/default_noexcept.pass.cpp | 58 --- .../flat.set.cons/dtor_noexcept.pass.cpp | 6 +- .../flat.set.cons/initializer_list.pass.cpp | 6 +- .../flat.set/flat.set.cons/iter_iter.pass.cpp | 6 +- .../flat.set/flat.set.cons/move.pass.cpp | 107 +++++- .../flat.set.cons/move_alloc.pass.cpp | 10 +- .../flat.set.cons/move_assign.pass.cpp | 141 ++++++- .../flat.set.cons/move_assign_clears.pass.cpp | 101 ----- .../move_assign_noexcept.pass.cpp | 85 ----- .../flat.set.cons/move_exceptions.pass.cpp | 58 --- .../flat.set.cons/move_noexcept.pass.cpp | 94 ----- .../flat.set/flat.set.cons/pmr.pass.cpp | 6 +- .../flat.set/flat.set.cons/range.pass.cpp | 6 +- .../flat.set.cons/sorted_container.pass.cpp | 6 +- .../sorted_initializer_list.pass.cpp | 10 +- .../flat.set.cons/sorted_iter_iter.pass.cpp | 6 +- .../flat.set.erasure/erase_if.pass.cpp | 20 +- .../erase_if_exceptions.pass.cpp | 7 +- .../flat.set.iterators/iterator.pass.cpp | 18 +- .../iterator_comparison.pass.cpp | 14 +- .../reverse_iterator.pass.cpp | 8 +- .../flat.set.modifiers/clear.pass.cpp | 18 +- .../flat.set.modifiers/emplace.pass.cpp | 25 +- .../flat.set.modifiers/emplace_hint.pass.cpp | 25 +- .../flat.set.modifiers/erase_iter.pass.cpp | 25 +- .../erase_iter_iter.pass.cpp | 24 +- .../flat.set.modifiers/erase_key.pass.cpp | 37 +- .../erase_key_transparent.pass.cpp | 34 +- .../flat.set.modifiers/extract.pass.cpp | 21 +- .../flat.set.modifiers/insert_cv.pass.cpp | 33 +- .../insert_initializer_list.pass.cpp | 42 ++- .../insert_iter_cv.pass.cpp | 23 +- .../insert_iter_iter.pass.cpp | 27 +- .../insert_iter_rv.pass.cpp | 43 ++- .../flat.set.modifiers/insert_range.pass.cpp | 38 +- .../flat.set.modifiers/insert_rv.pass.cpp | 42 ++- .../insert_sorted_initializer_list.pass.cpp | 35 +- .../insert_sorted_iter_iter.pass.cpp | 29 +- .../insert_transparent.pass.cpp | 21 +- .../flat.set.modifiers/replace.pass.cpp | 50 +-- .../flat.set.modifiers/swap_free.pass.cpp | 16 +- .../flat.set.modifiers/swap_member.pass.cpp | 14 +- .../flat.set/flat.set.observers/comp.pass.cpp | 6 +- .../flat.set.operations/contains.pass.cpp | 14 +- .../contains_transparent.pass.cpp | 17 +- .../flat.set.operations/count.pass.cpp | 14 +- .../count_transparent.pass.cpp | 16 +- .../flat.set.operations/equal_range.pass.cpp | 14 +- .../equal_range_transparent.pass.cpp | 16 +- .../flat.set.operations/find.pass.cpp | 14 +- .../find_transparent.pass.cpp | 16 +- .../flat.set.operations/lower_bound.pass.cpp | 14 +- .../lower_bound_transparent.pass.cpp | 16 +- .../flat.set.operations/upper_bound.pass.cpp | 14 +- .../upper_bound_transparent.pass.cpp | 17 +- .../container.adaptors/flat.set/helpers.h | 19 +- .../flat.set/incomplete_type.pass.cpp | 5 +- .../flat.set/op_compare.pass.cpp | 17 +- 72 files changed, 1214 insertions(+), 1087 deletions(-) delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp delete mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index c920632c453bf5..37e4c9f7c686b0 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP___FLAT_set_FLAT_SET_H -#define _LIBCPP___FLAT_set_FLAT_SET_H +#ifndef _LIBCPP___FLAT_SET_FLAT_SET_H +#define _LIBCPP___FLAT_SET_FLAT_SET_H #include <__algorithm/lexicographical_compare_three_way.h> #include <__algorithm/min.h> @@ -99,13 +99,6 @@ class flat_set { using const_reverse_iterator = std::reverse_iterator; using container_type = _KeyContainer; -private: - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __allocator_ctor_constraint = - uses_allocator::value; - - _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare>; - public: // [flat.set.cons], construct/copy/destroy _LIBCPP_HIDE_FROM_ABI @@ -178,31 +171,31 @@ class flat_set { : flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI explicit flat_set(const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { __sort_and_unique(); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( @@ -210,7 +203,7 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __keys, __comp) { @@ -219,12 +212,12 @@ class flat_set { } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __other, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_tag{}, __alloc, __other.__keys_, __other.__compare_) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other, const _Allocator& __alloc) # if _LIBCPP_HAS_EXCEPTIONS try @@ -239,14 +232,14 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert(__first, __last); } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { @@ -254,7 +247,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { @@ -262,7 +255,7 @@ class flat_set { } template - requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) + requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator::value) _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, _InputIterator __first, @@ -274,37 +267,37 @@ class flat_set { } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc) { insert_range(std::forward<_Range>(__rg)); } template <_ContainerCompatibleRange _Range, class _Allocator> - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { insert_range(std::forward<_Range>(__rg)); } template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(__il.begin(), __il.end(), __comp, __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} @@ -334,11 +327,8 @@ class flat_set { // iterators _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __keys_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __keys_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __keys_.end(); } _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } @@ -382,7 +372,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { return emplace(std::forward<_Kp>(__x)); } @@ -395,7 +385,7 @@ class flat_set { } template - requires(__is_compare_transparent && is_constructible_v) + requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { return emplace_hint(__hint, std::forward<_Kp>(__x)); } @@ -425,7 +415,7 @@ class flat_set { __reserve(ranges::size(__range)); } - __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); + __append_sort_merge_unique(std::forward<_Range>(__range)); } _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } @@ -468,7 +458,7 @@ class flat_set { } template - requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && + requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> && !is_convertible_v<_Kp &&, const_iterator>) _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { auto [__first, __last] = equal_range(__x); @@ -505,13 +495,13 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { return __find_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { return __find_impl(*this, __x); } @@ -519,7 +509,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { return contains(__x) ? 1 : 0; } @@ -527,7 +517,7 @@ class flat_set { _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { return find(__x) != end(); } @@ -541,13 +531,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { return ranges::lower_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { return ranges::lower_bound(__keys_, __x, __compare_); } @@ -561,13 +551,13 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { return ranges::upper_bound(__keys_, __x, __compare_); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { return ranges::upper_bound(__keys_, __x, __compare_); } @@ -581,12 +571,12 @@ class flat_set { } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { return __equal_range_impl(*this, __x); } template - requires __is_compare_transparent + requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { return __equal_range_impl(*this, __x); } @@ -611,14 +601,14 @@ class flat_set { }; template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_tag, const _Allocator& __alloc, _KeyCont&& __key_cont, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc, std::forward<_KeyCont>(__key_cont))), __compare_(std::forward<_CompArg>(__comp)...) {} template - requires __allocator_ctor_constraint<_Allocator> + requires uses_allocator::value _LIBCPP_HIDE_FROM_ABI flat_set(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) : __keys_(std::make_obj_using_allocator(__alloc)), __compare_(std::forward<_CompArg>(__comp)...) {} @@ -637,17 +627,30 @@ class flat_set { __keys_.erase(__dup_start, __keys_.end()); } - template - _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { - auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); - size_type __old_size = size(); - if constexpr (requires { __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); }) { - __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + template + _LIBCPP_HIDE_FROM_ABI void __append(_InputIterator __first, _InputIterator __last) { + __keys_.insert(__keys_.end(), std::move(__first), std::move(__last)); + } + + template + _LIBCPP_HIDE_FROM_ABI void __append(_Range&& __rng) { + if constexpr (requires { __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); }) { + // C++23 Sequence Container should have insert_range member function + __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); + } else if constexpr (ranges::common_range<_Range>) { + __keys_.insert(__keys_.end(), ranges::begin(__rng), ranges::end(__rng)); } else { - for (; __first != __last; ++__first) { - __keys_.insert(__keys_.end(), *__first); + for (auto&& __x : __rng) { + __keys_.insert(__keys_.end(), std::forward(__x)); } } + } + + template + _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_Args&&... __args) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); + size_type __old_size = size(); + __append(std::forward<_Args>(__args)...); if (size() != __old_size) { if constexpr (!_WasSorted) { ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); @@ -831,18 +834,18 @@ template struct uses_allocator, _Allocator> : bool_constant> {}; - template - _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type - erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { - auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); - auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { - return static_cast(__pred(e)); - }); - auto __res = __flat_set.__keys_.end() - __it; - __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); - __guard.__complete(); - return __res; - } +template +_LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type +erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { + auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { + return static_cast(__pred(e)); + }); + auto __res = __flat_set.__keys_.end() - __it; + __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); + __guard.__complete(); + return __res; +} _LIBCPP_END_NAMESPACE_STD @@ -850,4 +853,4 @@ _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS -#endif // _LIBCPP___FLAT_set_FLAT_SET_H +#endif // _LIBCPP___FLAT_SET_FLAT_SET_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp index 204df1d681af1b..223b92fc3e8e84 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m; @@ -38,11 +38,15 @@ void test() { assert(m.empty()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index cd7f424e00ece2..0489d886257911 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -24,7 +24,8 @@ #include "test_allocator.h" #include "test_macros.h" -int main(int, char**) { +void test() { + { using A1 = limited_allocator; using C = std::flat_set, std::vector>; @@ -59,5 +60,10 @@ int main(int, char**) { assert(c.max_size() <= max_dist); assert(c.max_size() <= alloc_max_size(std::allocator())); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp index 7c156e95ecb1c8..9f5ffdd0663513 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; using S = typename M::size_type; { @@ -56,11 +56,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp index acc0817d7cac4d..d14e883dd5e936 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp @@ -22,7 +22,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -55,6 +55,10 @@ int main(int, char**) { auto v = std::move(m).extract(); assert(v.get_allocator().get_id() == 5); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7f75f1e1611e3b..7e948d7c5fe976 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -33,7 +33,6 @@ void test() { m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); - LIBCPP_ASSERT(std::ranges::equal(m, expected)); } { M m = {10, 8}; @@ -44,13 +43,17 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp index b3bee18f5a936b..110757a1bb9ab6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -78,6 +78,10 @@ int main(int, char**) { auto keys = std::move(m).extract(); assert(keys.get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp index 3d1e6240c952e8..6b1246885bf527 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp @@ -36,7 +36,7 @@ void conversion_test(T); template concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -116,21 +116,16 @@ int main(int, char**) { auto m = M(ks, A(4)); // replaces the allocators assert(!ks.empty()); // it was an lvalue above assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); + auto keys = M(m).extract(); assert(keys.get_allocator() == A(4)); - } - { - // flat_set(container_type , const Allocator&) + // explicit(false) - using A = test_allocator; - using M = std::flat_set, std::deque>; static_assert(ImplicitlyConstructible&, const A&>); - auto ks = std::deque({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); - M m = {ks, A(4)}; // implicit ctor - assert(!ks.empty()); // it was an lvalue above - assert((m == M{1, 2, 3})); - auto keys = std::move(m).extract(); - assert(keys.get_allocator() == A(4)); + M m2 = {ks, A(4)}; // implicit ctor + assert(!ks.empty()); // it was an lvalue above + assert(m2 == m); + auto keys2 = std::move(m).extract(); + assert(keys2.get_allocator() == A(4)); } { // flat_set(container_type , key_compare, const Allocator&) @@ -153,6 +148,10 @@ int main(int, char**) { keys = std::move(m2).extract(); assert(keys.get_allocator() == A(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp index f1dbc955e1b0de..1ba550d98f01f6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp @@ -21,7 +21,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; std::vector> ks({1, 3, 5}, test_allocator(6)); @@ -59,6 +59,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == other_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp index 59fb9d0a38366f..5011bd20030641 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp @@ -23,7 +23,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -58,6 +58,10 @@ int main(int, char**) { auto keys2 = std::move(mo).extract(); assert(keys2.get_allocator() == test_allocator(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp deleted file mode 100644 index 169b469f3bca68..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.addressof.compile.pass.cpp +++ /dev/null @@ -1,30 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(const flat_set& s); - -// Validate whether the container can be copy-assigned (move-assigned, swapped) -// with an ADL-hijacking operator& - -#include -#include - -#include "test_macros.h" -#include "operator_hijacker.h" - -void test() { - std::flat_set so; - std::flat_set s; - s = so; - s = std::move(so); - swap(s, so); -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp index cdd5045f4bb9f7..695363e3aeabab 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp @@ -17,11 +17,12 @@ #include #include +#include "operator_hijacker.h" #include "test_macros.h" #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // test_allocator is not propagated using C = test_less; @@ -81,5 +82,19 @@ int main(int, char**) { m = static_cast(m); assert((m == M{{1, 2}})); } + { + // Validate whether the container can be copy-assigned (move-assigned, swapped) + // with an ADL-hijacking operator& + std::flat_set so; + std::flat_set s; + s = so; + s = std::move(so); + swap(s, so); + } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp index 612e64a7c42f23..607fe0d1a9713a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -26,24 +26,21 @@ #include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" -using P = std::pair; -using PC = std::pair; - void test_copy() { { - std::flat_set source = {{1, 2}, {2, 3}}; + std::flat_set source = {1, 2}; std::flat_set s(source); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s{source}; // braces instead of parens ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); } { - std::flat_set> source = {{1, 2}, {2, 3}}; + std::flat_set> source = {1, 2}; std::flat_set s(source, std::allocator()); ASSERT_SAME_TYPE(decltype(s), decltype(source)); assert(s == source); @@ -52,275 +49,259 @@ void test_copy() { void test_containers() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({1, 2, 3, INT_MAX}, test_allocator(0, 42)); - std::deque> sorted_vs({1, 2, 5, 4}, test_allocator(0, 43)); - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + int expected[] = {1, 2, 3, INT_MAX}; { - std::flat_set s(ks, vs); + std::flat_set s(ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs); + std::flat_set s(std::sorted_unique, sorted_ks); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, test_allocator(0, 44)); + std::flat_set s(ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_containers_compare() { std::deque> ks({1, 2, 1, INT_MAX, 3}, test_allocator(0, 42)); - std::deque> vs({1, 2, 1, 4, 5}, test_allocator(0, 43)); std::deque> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator(0, 42)); - std::deque> sorted_vs({4, 5, 2, 1}, test_allocator(0, 43)); - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + int expected[] = {INT_MAX, 3, 2, 1}; { - std::flat_set s(ks, vs, std::greater()); + std::flat_set s(ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater()); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 43); + assert(std::move(s).extract().get_allocator().get_id() == 42); } { - std::flat_set s(ks, vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } { - std::flat_set s(std::sorted_unique, sorted_ks, sorted_vs, std::greater(), test_allocator(0, 44)); + std::flat_set s(std::sorted_unique, sorted_ks, std::greater(), test_allocator(0, 44)); - ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks), decltype(vs)>); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, decltype(ks)>); assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 44); - assert(s.values().get_allocator().get_id() == 44); + assert(std::move(s).extract().get_allocator().get_id() == 44); } } void test_iter_iter() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + const int arr[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arr[] = {1, 2, 3, INT_MAX}; + const int arrc[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arrc[] = {1, 2, 3, INT_MAX}; { std::flat_set m(std::begin(arr), std::end(arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::begin(arrc), std::end(arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc)); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); assert(std::ranges::equal(m, sorted_arr)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.begin(), mo.end()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::flat_set mo; + std::flat_set mo; std::flat_set m(mo.cbegin(), mo.cend()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s = {source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); - } - { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; - std::flat_set s{source, source + 3}; // flat_set(InputIterator, InputIterator) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 3); + // This does not deduce to flat_set(InputIterator, InputIterator) + // But deduces to flat_set(initializer_list) + int source[3] = {1, 2, 3}; + std::flat_set s = {source, source + 3}; + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 2); } { - std::pair source[3] = {{1, 1}, {2, 2}, {3, 3}}; + int source[3] = {1, 2, 3}; std::flat_set s{std::sorted_unique, source, source + 3}; // flat_set(sorted_unique_t, InputIterator, InputIterator) - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); assert(s.size() == 3); } } void test_iter_iter_compare() { - const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m(std::begin(arr), std::end(arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::begin(arrc), std::end(arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set mo; - std::flat_set m(mo.begin(), mo.end(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } - { - std::flat_set mo; - std::flat_set m(mo.cbegin(), mo.cend(), C()); - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - } + // const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + // const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m(std::begin(arr), std::end(arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.begin(), mo.end(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } + // { + // std::flat_set mo; + // std::flat_set m(mo.cbegin(), mo.cend(), C()); + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // } } void test_initializer_list() { - const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - { - std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - } - { - using M = std::flat_set; - M m; - std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) - ASSERT_SAME_TYPE(decltype(s), std::flat_set); - assert(s.size() == 1); - assert(s[m] == m); - } + // const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; + // { + // std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // } + // { + // using M = std::flat_set; + // M m; + // std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) + // ASSERT_SAME_TYPE(decltype(s), std::flat_set); + // assert(s.size() == 1); + // assert(s[m] == m); + // } } void test_initializer_list_compare() { - const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - using C = std::greater; - { - std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } - { - std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); - - ASSERT_SAME_TYPE(decltype(m), std::flat_set); - assert(std::ranges::equal(m, sorted_arr)); - } + // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; + // using C = std::greater; + // { + // std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } + // { + // std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); + + // ASSERT_SAME_TYPE(decltype(m), std::flat_set); + // assert(std::ranges::equal(m, sorted_arr)); + // } } void test_from_range() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; - { - std::flat_set s(std::from_range, r); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; + // { + // std::flat_set s(std::from_range, r); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } void test_from_range_compare() { - std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; - { - std::flat_set s(std::from_range, r, std::greater()); - ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - assert(std::ranges::equal(s, expected)); - } - { - std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); - ASSERT_SAME_TYPE( - decltype(s), - std::flat_set, - std::vector>, - std::vector>>); - assert(std::ranges::equal(s, expected)); - assert(s.keys().get_allocator().get_id() == 42); - assert(s.values().get_allocator().get_id() == 42); - } + // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; + // const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; + // { + // std::flat_set s(std::from_range, r, std::greater()); + // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + // assert(std::ranges::equal(s, expected)); + // } + // { + // std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + // ASSERT_SAME_TYPE( + // decltype(s), + // std::flat_set, + // std::vector>, + // std::vector>>); + // assert(std::ranges::equal(s, expected)); + // assert(s.keys().get_allocator().get_id() == 42); + // assert(s.values().get_allocator().get_id() == 42); + // } } int main(int, char**) { @@ -335,7 +316,7 @@ int main(int, char**) { test_from_range(); test_from_range_compare(); - AssociativeContainerDeductionGuidesSfinaeAway>(); + AssociativeContainerDeductionGuidesSfinaeAway>(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp index 64b0bfcb383a72..292af96c61582f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -19,9 +19,10 @@ #include #include -#include "test_macros.h" #include "min_allocator.h" +#include "MoveOnly.h" #include "test_allocator.h" +#include "test_macros.h" struct DefaultCtableComp { explicit DefaultCtableComp() { default_constructed_ = true; } @@ -29,7 +30,12 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +struct ThrowingCtorComp { + ThrowingCtorComp() noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +void test() { { std::flat_set m; assert(m.empty()); @@ -60,6 +66,32 @@ int main(int, char**) { assert(m.key_comp().default_constructed_); } } +#if defined(_LIBCPP_VERSION) + { + using C = std::flat_set; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set, std::vector>>; + static_assert(std::is_nothrow_default_constructible_v); + C c; + } +#endif // _LIBCPP_VERSION + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } + { + using C = std::flat_set; + static_assert(!std::is_nothrow_default_constructible_v); + C c; + } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp deleted file mode 100644 index b4a3b6de205a31..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default_noexcept.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set() -// noexcept( -// is_nothrow_default_constructible_v && -// is_nothrow_default_constructible_v); - -// This tests a conforming extension - -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -struct ThrowingCtorComp { - ThrowingCtorComp() noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -int main(int, char**) { -#if defined(_LIBCPP_VERSION) - { - using C = std::flat_set; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set, std::vector>>; - static_assert(std::is_nothrow_default_constructible_v); - C c; - } -#endif // _LIBCPP_VERSION - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - { - using C = std::flat_set; - static_assert(!std::is_nothrow_default_constructible_v); - C c; - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp index c0d315c0ce74b4..fa1e2478af4599 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp @@ -27,7 +27,7 @@ struct ThrowingDtorComp { ~ThrowingDtorComp() noexcept(false) {} }; -int main(int, char**) { +void test() { { using C = std::flat_set; static_assert(std::is_nothrow_destructible_v); @@ -52,6 +52,10 @@ int main(int, char**) { C c; } #endif // _LIBCPP_VERSION +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp index cd2319e91f760d..9aed5c88ee7268 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp @@ -35,7 +35,7 @@ struct DefaultCtableComp { bool default_constructed_ = false; }; -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -146,6 +146,10 @@ int main(int, char**) { M m({5, 2, 2, 3, 1, 3}, {}, a); assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp index 65eebc21a66c4c..2d0b07c9155fdb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp @@ -29,7 +29,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -131,6 +131,10 @@ int main(int, char**) { LIBCPP_ASSERT(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp index 69b340ad09fe15..b2853844b986c6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp @@ -25,7 +25,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +void test() { { using C = test_less; using A = test_allocator; @@ -79,5 +79,110 @@ int main(int, char**) { LIBCPP_ASSERT(m1.empty()); LIBCPP_ASSERT(m1.size() == 0); } +} + +template +struct ThrowingMoveAllocator { + using value_type = T; + explicit ThrowingMoveAllocator() = default; + ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; + ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} + T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } + void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } + friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; +}; + +struct ThrowingMoveComp { + ThrowingMoveComp() = default; + ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} + ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} + bool operator()(const auto&, const auto&) const { return false; } +}; + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +void test_move_noexcept() { + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } + { + using C = std::flat_set, std::deque>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#if _LIBCPP_VERSION + { + // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators + using C = std::flat_set, std::deque>>; + static_assert(!std::is_nothrow_move_constructible_v>>); + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +#endif // _LIBCPP_VERSION + { + // Comparator fails to be nothrow-move-constructible + using C = std::flat_set; + static_assert(!std::is_nothrow_move_constructible_v); + C c; + C d = std::move(c); + } +} + +#if !defined(TEST_HAS_NO_EXCEPTIONS) +static int countdown = 0; + +struct EvilContainer : std::vector { + EvilContainer() = default; + EvilContainer(EvilContainer&& rhs) { + // Throw on move-construction. + if (--countdown == 0) { + rhs.insert(rhs.end(), 0); + rhs.insert(rhs.end(), 0); + throw 42; + } + } +}; + +void test_move_exception() { + { + using M = std::flat_set, EvilContainer>; + M mo = {1, 2, 3}; + countdown = 1; + try { + M m = std::move(mo); + assert(false); // not reached + } catch (int x) { + assert(x == 42); + } + // The source flat_set maintains its class invariant. + check_invariant(mo); + LIBCPP_ASSERT(mo.empty()); + } +} +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + +int main(int, char**) { + test(); + test_move_noexcept(); +#if !defined(TEST_HAS_NO_EXCEPTIONS) + test_move_exception(); +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp index fc7f68d8c967ad..489b6ff36324b3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp @@ -24,7 +24,7 @@ #include "../../../test_compare.h" #include "test_allocator.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -53,7 +53,7 @@ int main(int, char**) { assert(m.size() == 3); auto keys = std::move(m).extract(); assert(keys.get_allocator() == A(3)); - assert(std::ranges::equal(keys, expected )); + assert(std::ranges::equal(keys, expected)); // The original flat_set is moved-from. assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); @@ -63,13 +63,17 @@ int main(int, char**) { } { // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, CopyOnlyVector>; + using M = std::flat_set, CopyOnlyVector>; M m1 = M({1, 2, 3}); M m2(std::move(m1), std::allocator{}); assert(m2.size() == 3); check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index b16dc38dd40285..e55a0516ed1bed 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -22,11 +22,144 @@ #include "test_macros.h" #include "MoveOnly.h" +#include "../helpers.h" #include "../../../test_compare.h" #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +struct MoveNegates { + int value_ = 0; + MoveNegates() = default; + MoveNegates(int v) : value_(v) {} + MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } + MoveNegates& operator=(MoveNegates&& rhs) { + value_ = rhs.value_; + rhs.value_ = -rhs.value_; + return *this; + } + ~MoveNegates() = default; + auto operator<=>(const MoveNegates&) const = default; +}; + +struct MoveClears { + int value_ = 0; + MoveClears() = default; + MoveClears(int v) : value_(v) {} + MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } + MoveClears& operator=(MoveClears&& rhs) { + value_ = rhs.value_; + rhs.value_ = 0; + return *this; + } + ~MoveClears() = default; + auto operator<=>(const MoveClears&) const = default; +}; + +void test_move_assign_clears() { + // Preserves the class invariant for the moved-from flat_set. + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + using M = std::flat_set>; + M m = M(expected, expected + 8); + M m2 = M(expected, expected + 3); + + m2 = std::move(m); + + assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); + LIBCPP_ASSERT(m.empty()); + assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted + assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates + m.insert(1); + m.insert(2); + assert(m.contains(1)); + assert(m.find(2) != m.end()); + } + { + // moved-from object maintains invariant if one of underlying container does not clear after move + using M = std::flat_set, std::vector>; + M m1 = M({1, 2, 3}); + M m2 = M({1, 2}); + m2 = std::move(m1); + assert(m2.size() == 3); + check_invariant(m1); + LIBCPP_ASSERT(m1.empty()); + } +} + +struct MoveSensitiveComp { + MoveSensitiveComp() noexcept(false) = default; + MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; + MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } + MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; + MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { + rhs.is_moved_from_ = true; + return *this; + } + bool operator()(const auto&, const auto&) const { return false; } + bool is_moved_from_ = false; +}; + +struct MoveThrowsComp { + MoveThrowsComp(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp(const MoveThrowsComp&) noexcept(true); + MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); + MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); + bool operator()(const auto&, const auto&) const; +}; + +void test_move_assign_no_except() { + // This tests a conforming extension + + { + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + static_assert(!std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + using C = std::flat_set, std::vector>>; + LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); + } + { + // Test with a comparator that throws on move-assignment. + using C = std::flat_set; + LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); + } + { + // Test with a container that throws on move-assignment. + using C = std::flat_set, std::pmr::vector>; + static_assert(!std::is_nothrow_move_assignable_v); + } +} + +void test() { { using C = test_less; using A1 = test_allocator; @@ -64,6 +197,12 @@ int main(int, char**) { assert(ks.get_allocator() == A()); assert(mo.empty()); } +} + +int main(int, char**) { + test(); + test_move_assign_clears(); + test_move_assign_no_except(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp deleted file mode 100644 index 50817f4be8a812..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_clears.pass.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&&); -// Preserves the class invariant for the moved-from flat_set. - -#include -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -struct MoveNegates { - int value_ = 0; - MoveNegates() = default; - MoveNegates(int v) : value_(v) {} - MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; } - MoveNegates& operator=(MoveNegates&& rhs) { - value_ = rhs.value_; - rhs.value_ = -rhs.value_; - return *this; - } - ~MoveNegates() = default; - auto operator<=>(const MoveNegates&) const = default; -}; - -struct MoveClears { - int value_ = 0; - MoveClears() = default; - MoveClears(int v) : value_(v) {} - MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; } - MoveClears& operator=(MoveClears&& rhs) { - value_ = rhs.value_; - rhs.value_ = 0; - return *this; - } - ~MoveClears() = default; - auto operator<=>(const MoveClears&) const = default; -}; - -int main(int, char**) { - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - using M = std::flat_set>; - M m = M(expected, expected + 8); - M m2 = M(expected, expected + 3); - - m2 = std::move(m); - - assert(std::equal(m2.begin(), m2.end(), expected, expected + 8)); - LIBCPP_ASSERT(m.empty()); - assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted - assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates - m.insert(1); - m.insert(2); - assert(m.contains(1)); - assert(m.find(2) != m.end()); - } - { - // moved-from object maintains invariant if one of underlying container does not clear after move - using M = std::flat_set, std::vector>; - M m1 = M({1, 2, 3}); - M m2 = M({1, 2}); - m2 = std::move(m1); - assert(m2.size() == 3); - check_invariant(m1); - LIBCPP_ASSERT(m1.empty()); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp deleted file mode 100644 index 86f3568f0d67a6..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign_noexcept.pass.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set& operator=(flat_set&& c) -// noexcept( -// is_nothrow_move_assignable::value && -// is_nothrow_move_assignable::value && -// is_nothrow_copy_assignable::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include - -#include "MoveOnly.h" -#include "test_allocator.h" -#include "test_macros.h" - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -struct MoveThrowsComp { - MoveThrowsComp(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp(const MoveThrowsComp&) noexcept(true); - MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false); - MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true); - bool operator()(const auto&, const auto&) const; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - static_assert(!std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - using C = std::flat_set, std::vector>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v); - } - { - // Test with a comparator that throws on move-assignment. - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v); - } - { - // Test with a container that throws on move-assignment. - using C = std::flat_set, std::pmr::vector>; - static_assert(!std::is_nothrow_move_assignable_v); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp deleted file mode 100644 index 17e4e40387606c..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_exceptions.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 -// UNSUPPORTED: no-exceptions - -// - -// flat_set(flat_set&& s); -// If any member function in [flat.map.defn] exits via an exception, the invariant is restored. - -#include -#include -#include -#include -#include -#include - -#include "../helpers.h" -#include "test_macros.h" - -static int countdown = 0; - -struct EvilContainer : std::vector { - EvilContainer() = default; - EvilContainer(EvilContainer&& rhs) { - // Throw on move-construction. - if (--countdown == 0) { - rhs.insert(rhs.end(), 0); - rhs.insert(rhs.end(), 0); - throw 42; - } - } -}; - -int main(int, char**) { - { - using M = std::flat_set, EvilContainer>; - M mo = {1, 2, 3}; - countdown = 1; - try { - M m = std::move(mo); - assert(false); // not reached - } catch (int x) { - assert(x == 42); - } - // The source flat_set maintains its class invariant. - check_invariant(mo); - LIBCPP_ASSERT(mo.empty()); - } - - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp deleted file mode 100644 index 49d1151fd8a993..00000000000000 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_noexcept.pass.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -// - -// flat_set(flat_set&&) -// noexcept(is_nothrow_move_constructible::value && -// is_nothrow_move_constructible::value && -// is_nothrow_copy_constructible::value); - -// This tests a conforming extension - -#include -#include -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "MoveOnly.h" -#include "test_allocator.h" - -template -struct ThrowingMoveAllocator { - using value_type = T; - explicit ThrowingMoveAllocator() = default; - ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default; - ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {} - T* allocate(std::ptrdiff_t n) { return std::allocator().allocate(n); } - void deallocate(T* p, std::ptrdiff_t n) { return std::allocator().deallocate(p, n); } - friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default; -}; - -struct ThrowingMoveComp { - ThrowingMoveComp() = default; - ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {} - ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {} - bool operator()(const auto&, const auto&) const { return false; } -}; - -struct MoveSensitiveComp { - MoveSensitiveComp() noexcept(false) = default; - MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default; - MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; } - MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default; - MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) { - rhs.is_moved_from_ = true; - return *this; - } - bool operator()(const auto&, const auto&) const { return false; } - bool is_moved_from_ = false; -}; - -int main(int, char**) { - { - using C = std::flat_set; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - { - using C = std::flat_set, std::deque>>; - LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#if _LIBCPP_VERSION - { - // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators - using C = std::flat_set, std::deque>>; - static_assert(!std::is_nothrow_move_constructible_v>>); - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } -#endif // _LIBCPP_VERSION - { - // Comparator fails to be nothrow-move-constructible - using C = std::flat_set; - static_assert(!std::is_nothrow_move_constructible_v); - C c; - C d = std::move(c); - } - return 0; -} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp index 785718d2eed333..1a4eafa8802918 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp @@ -28,7 +28,7 @@ #include "test_allocator.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // flat_set(const Allocator& a); using M = std::flat_set, std::pmr::vector>; @@ -317,6 +317,10 @@ int main(int, char**) { assert(vm[0].key_comp() == C(4)); assert(std::move(vm[0]).extract().get_allocator().resource() == &mr); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp index bb9f99c228bfec..bd7b5c12432e96 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp @@ -56,7 +56,7 @@ static_assert( !std:: is_constructible_v>, std::less, std::allocator>); -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -168,6 +168,10 @@ int main(int, char**) { assert(std::ranges::equal(m, expected)); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp index 2d442d49667bd0..873ff32b62936a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -138,6 +138,10 @@ int main(int, char**) { assert(m2 == m); assert(std::move(m2).extract().get_allocator() == A(6)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp index 01956a78c7f48d..a8dac35aefee81 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp @@ -33,10 +33,10 @@ template std::initializer_list il = {1, 2, 4, 5}; -const auto il1 = il; -const auto il2 = il; +void test() { + const auto il1 = il; + const auto il2 = il; -int main(int, char**) { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -145,6 +145,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp index b5229a84dd5133..b184ee9c3f5aba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp @@ -28,7 +28,7 @@ #include "test_macros.h" #include "../../../test_compare.h" -int main(int, char**) { +void test() { { // The constructors in this subclause shall not participate in overload // resolution unless uses_allocator_v is true. @@ -151,6 +151,10 @@ int main(int, char**) { assert((m == M{1, 2, 4, 5})); assert(std::move(m).extract().get_allocator() == A1(5)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp index 134db83aef3cad..806779bc7d16bc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp @@ -49,7 +49,7 @@ void test0( } template -void test() { +void test_one() { // Test all the plausible signatures for this predicate. auto is1 = [](typename S::const_reference v) { return v == 1; }; auto is2 = [](typename S::value_type v) { return v == 2; }; @@ -76,14 +76,18 @@ void test() { test0({1, 2, 3}, False, {1, 2, 3}, 0); } +void test() { + test_one>(); + test_one, std::vector>>>(); + test_one, std::vector>>>(); + test_one, std::deque>>>(); + test_one, std::deque>>>(); + test_one>(); + test_one>(); +} + int main(int, char**) { - test>(); - test, std::vector>>>(); - test, std::vector>>>(); - test, std::deque>>>(); - test, std::deque>>>(); - test>(); - test>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp index 6bbe1ad4f01670..37b4a40f0165cf 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp @@ -65,7 +65,7 @@ struct ErasurePredicate { bool operator()(const auto& x) const { return (3 <= x && x <= 5); } }; -int main(int, char**) { +void test() { const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; { using M = std::flat_set; @@ -124,5 +124,10 @@ int main(int, char**) { } } } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp index c07297a141ad10..846bcff63d7736 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp @@ -30,7 +30,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -67,15 +67,15 @@ void test() { assert(i == m.begin()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::iterator ii1{}, ii2{}; C::iterator ii4 = ii1; C::const_iterator cii{}; @@ -88,6 +88,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp index 29441dcc57d40e..3027cdd4076eea 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using KI = typename KeyContainer::iterator; @@ -144,11 +144,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp index a16383cdcf5383..d1e4cef3de19e8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" #include -int main(int, char**) { +void test() { { using M = std::flat_set, std::deque>; M m = {1, 2, 3, 4}; @@ -69,7 +69,7 @@ int main(int, char**) { } { // N3644 testing - using C = std::flat_set; + using C = std::flat_set; C::reverse_iterator ii1{}, ii2{}; C::reverse_iterator ii4 = ii1; C::const_reverse_iterator cii{}; @@ -82,6 +82,10 @@ int main(int, char**) { assert(!(ii1 != cii)); assert(!(cii != ii1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp index 221a13fa057577..efa13a51c30bb3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp @@ -38,7 +38,7 @@ static_assert(NoExceptClear, ThrowOnMoveContai #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -50,13 +50,17 @@ void test() { assert(m.size() == 0); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp index 95f7a3c5f5d34a..79800e894afbfc 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp @@ -28,7 +28,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -121,21 +121,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp index de855d5e5c3009..b3bd8adf0c35d8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp @@ -27,7 +27,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = M::iterator; @@ -134,21 +134,26 @@ void test_emplaceable() { assert(*m.begin() == Emplaceable(1, 3.5)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>(); test_emplaceable>>(); +} - { - auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; - test_emplace_exception_guarantee(emplace_func); - } +void test_exception() { + auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); }; + test_emplace_exception_guarantee(emplace_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp index 386af04d26e9a2..42562b84b4e22d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp @@ -27,7 +27,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -106,16 +106,21 @@ void test() { assert(i8 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp index 7416977844e5df..d402a7ba0285ec 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using I = M::iterator; @@ -77,15 +77,21 @@ void test() { assert(i4 == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; + test_erase_exception_guarantee(erase_function); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); }; - test_erase_exception_guarantee(erase_function); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp index 25d4f4af19608b..d81422d3871876 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp @@ -26,7 +26,7 @@ #include "min_allocator.h" template > -void test() { +void test_one() { using M = std::flat_set; auto make = [](std::initializer_list il) { @@ -70,22 +70,27 @@ void test() { assert(m.empty()); } -int main(int, char**) { - test>(); - test, std::greater<>>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one, std::greater<>>(); + test_one>(); + test_one>(); + test_one>>(); +} - { - auto erase_function = [](auto& m, auto key_arg) { - using Map = std::decay_t; - using Key = typename Map::key_type; - const Key key{key_arg}; - m.erase(key); - }; - test_erase_exception_guarantee(erase_function); - } +void test_exception() { + auto erase_function = [](auto& m, auto key_arg) { + using Map = std::decay_t; + using Key = typename Map::key_type; + const Key key{key_arg}; + m.erase(key); + }; + test_erase_exception_guarantee(erase_function); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp index cbf7cac603806d..c383844eb4973e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp @@ -50,7 +50,7 @@ struct HeterogeneousKey { }; template -void test_simple() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -86,11 +86,11 @@ void test_transparent_comparator() { assert(m == expected); } -int main(int, char**) { - test_simple>(); - test_simple>(); - test_simple>(); - test_simple>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); test_transparent_comparator>(); test_transparent_comparator>(); @@ -129,14 +129,20 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } - { - auto erase_transparent = [](auto& m, auto key_arg) { - using Set = std::decay_t; - using Key = typename Set::key_type; - m.erase(Transparent{key_arg}); - }; - test_erase_exception_guarantee(erase_transparent); - } +} + +void test_exception() { + auto erase_transparent = [](auto& m, auto key_arg) { + using Set = std::decay_t; + using Key = typename Set::key_type; + m.erase(Transparent{key_arg}); + }; + test_erase_exception_guarantee(erase_transparent); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp index c3bbffabb90a08..dfa21a807f0254 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp @@ -33,7 +33,7 @@ static_assert(!CanExtract const&>); static_assert(!CanExtract const&&>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; M m = M({1, 2, 3}); @@ -45,11 +45,12 @@ void test() { LIBCPP_ASSERT(m.empty()); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { // extracted object maintains invariant if the underlying container does not clear after move using M = std::flat_set, CopyOnlyVector>; @@ -59,7 +60,9 @@ int main(int, char**) { check_invariant(m); LIBCPP_ASSERT(m.empty()); } +} +void test_exception() { { #ifndef TEST_HAS_NO_EXCEPTIONS using KeyContainer = ThrowOnMoveContainer; @@ -79,5 +82,11 @@ int main(int, char**) { } #endif } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp index c0ddadc3006987..e0cb80f74462cd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = std::pair; @@ -59,20 +59,25 @@ void test() { assert(*r.first == 3); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using value_type = typename std::decay_t::value_type; + const value_type p(key_arg); + m.insert(p); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(p); - }; - test_emplace_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp index 7381514a70eabb..bf94fd9f5b11fd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp @@ -23,12 +23,12 @@ #include "min_allocator.h" template -void test() { - using Key = typename KeyContainer::value_type; - using M = std::flat_set, KeyContainer>; - using V = typename M::value_type; +void test_one() { + using Key = typename KeyContainer::value_type; + using M = std::flat_set, KeyContainer>; + using V = typename M::value_type; - M m = {1,1,1,3,3,3}; + M m = {1, 1, 1, 3, 3, 3}; m.insert({ 4, 4, @@ -48,20 +48,26 @@ void test() { assert(*std::next(m.begin(), 3) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); + test_exception(); - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(il); - }; - test_insert_range_exception_guarantee(insert_func); - } return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index c343d53a62215a..d6791853e0debd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using R = typename M::iterator; @@ -55,13 +55,15 @@ void test() { assert(*r == 3); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; using value_type = typename FlatSet::value_type; @@ -69,6 +71,11 @@ int main(int, char**) { m.insert(m.begin(), p); }; test_emplace_exception_guarantee(insert_func); - } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp index d20a8ef8fdd92d..8063686c960ed3 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using M = std::flat_set, KeyContainer>; int ar1[] = { @@ -73,15 +73,22 @@ void test() { M expected2{0, 1, 2, 3, 4}; assert(m == expected2); } + +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp index 84b6c7fc1d34f6..d29de98e4d3ddb 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp @@ -22,7 +22,7 @@ #include "test_macros.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -49,25 +49,30 @@ void test() { assert(*r == V(3)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(m.begin(), std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(m.begin(), std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp index 536307252c6405..ed33827a7355c9 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp @@ -39,7 +39,7 @@ static_assert(!CanInsertRange*>>) static_assert(!CanInsertRange*>>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -75,31 +75,29 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { - // Items are forwarded correctly from the input range (P2767). + // Items are forwarded correctly from the input range. MoveOnly a[] = {3, 1, 4, 1, 5}; std::flat_set m; m.insert_range(a | std::views::as_rvalue); MoveOnly expected[] = {1, 3, 4, 5}; assert(std::ranges::equal(m, expected)); } - { - // The element type of the range doesn't need to be std::pair (P2767). - int pa[] = {3, 1, 4, 1, 5}; - std::deque> a(pa, pa + 5); - std::flat_set m; - m.insert_range(a); - int expected[] = {1, 3, 4, 5}; - assert(std::ranges::equal(m, expected)); - } - { - auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; - test_insert_range_exception_guarantee(insert_func); - } +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); }; + test_insert_range_exception_guarantee(insert_func); +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp index 7d95f0521eb1f6..faf74142caff5c 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp @@ -25,7 +25,7 @@ #include "../helpers.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; using R = std::pair; @@ -57,24 +57,30 @@ void test() { assert(*r.first == V(3)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + value_type p(key_arg); + m.insert(std::move(p)); + }; + test_emplace_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test>>(); - test>>(); - { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - value_type p(key_arg); - m.insert(std::move(p)); - }; - test_emplace_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp index fa5bf86830daec..38c36d1befaa7c 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; using V = Key; @@ -38,21 +38,26 @@ void test() { assert(*std::next(m.begin(), 4) == V(4)); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + std::initializer_list il = {newValues[0]}; + m.insert(std::sorted_unique, il); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - std::initializer_list il = {newValues[0]}; - m.insert(std::sorted_unique, il); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp index ef7b8391cee33c..6258c4dbfdcbba 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp @@ -36,7 +36,7 @@ static_assert(!CanInsert); static_assert(!CanInsert, cpp20_input_iterator>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -60,18 +60,23 @@ void test() { assert(m == expected2); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + +void test_exception() { + auto insert_func = [](auto& m, const auto& newValues) { + m.insert(std::sorted_unique, newValues.begin(), newValues.end()); + }; + test_insert_range_exception_guarantee(insert_func); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); - - { - auto insert_func = [](auto& m, const auto& newValues) { - m.insert(std::sorted_unique, newValues.begin(), newValues.end()); - }; - test_insert_range_exception_guarantee(insert_func); - } + test(); + test_exception(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp index 72d7261a182547..d2ddf95aac2bb7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -57,7 +57,7 @@ struct CompareCounter { }; template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -121,11 +121,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // no ambiguity between insert(pos, P&&) and insert(first, last) @@ -139,6 +139,9 @@ int main(int, char**) { ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator); ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void); } +} + +void test_exception() { { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; @@ -165,5 +168,11 @@ int main(int, char**) { }; test_emplace_exception_guarantee(insert_func_iter); } +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp index 49cb6eb6163c90..fca33bd41449e0 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp @@ -31,7 +31,7 @@ static_assert(CanReplace>); static_assert(!CanReplace&>); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -43,30 +43,36 @@ void test() { assert(std::ranges::equal(m, expected_keys)); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} - { +void test_exception() { #ifndef TEST_HAS_NO_EXCEPTIONS - using KeyContainer = ThrowOnMoveContainer; - using M = std::flat_set; + using KeyContainer = ThrowOnMoveContainer; + using M = std::flat_set; - M m; - m.emplace(1); - m.emplace(2); - try { - KeyContainer new_keys{3, 4}; - m.replace(std::move(new_keys)); - assert(false); - } catch (int) { - check_invariant(m); - // In libc++, we clear the map - LIBCPP_ASSERT(m.size() == 0); - } -#endif + M m; + m.emplace(1); + m.emplace(2); + try { + KeyContainer new_keys{3, 4}; + m.replace(std::move(new_keys)); + assert(false); + } catch (int) { + check_invariant(m); + // In libc++, we clear the map + LIBCPP_ASSERT(m.size() == 0); } +#endif +} + +int main(int, char**) { + test(); + test_exception(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp index bc7baa67e52a59..ed13ba1ef3fea7 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp @@ -24,6 +24,8 @@ #include "test_macros.h" #include "../helpers.h" +#include "check_assertion.h" + // test noexcept template @@ -38,7 +40,7 @@ static_assert(NoExceptAdlSwap, ThrowOnMoveCont #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; @@ -84,11 +86,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp index b0b06a9499efc7..1eac55d768ce0b 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp @@ -37,7 +37,7 @@ static_assert(NoExceptMemberSwap, ThrowOnMoveC #endif template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; { @@ -82,11 +82,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp index 971b5e1c338dd1..ba2c428c9e30e2 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp @@ -21,7 +21,7 @@ #include "test_macros.h" -int main(int, char**) { +void test() { { using M = std::flat_set; using Comp = std::less; // the default @@ -67,6 +67,10 @@ int main(int, char**) { assert(vc(1, 2)); assert(!vc(2, 1)); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp index b14da66f611301..e23683f6f28945 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp index 507560608952b0..0cdff44d11274f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanContains); static_assert(!CanContains); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.contains(Transparent{"g"}) == false); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,5 +66,10 @@ int main(int, char**) { assert(b); assert(transparent_used); } +} + +int main(int, char**) { + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp index 478f615358b606..017f0fed3e9816 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp @@ -23,7 +23,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using S = typename KeyContainer::size_type; @@ -59,11 +59,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp index b591258f74399c..0c5ce9d5799651 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp @@ -34,7 +34,7 @@ static_assert(!CanCount); static_assert(!CanCount); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -51,11 +51,11 @@ void test() { assert(m.count(Transparent{"g"}) == 0); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -66,6 +66,10 @@ int main(int, char**) { assert(n == 1); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp index a088b7fee17d2c..b55cbe2ac42a00 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -67,11 +67,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp index ede5d91e19b9fd..97c4af19eaef37 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanEqualRange); static_assert(!CanEqualRange); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -77,11 +77,11 @@ void test() { test_not_found(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -92,6 +92,10 @@ int main(int, char**) { assert(p.first != p.second); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp index cf0dd2d1dd831c..9ee8f043e1d9cd 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp @@ -25,7 +25,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set, KeyContainer>; M m = {1, 2, 4, 5, 8}; @@ -43,11 +43,15 @@ void test() { assert(std::as_const(m).find(9) == m.end()); } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp index 730a57b0a6cb85..cc8ea12bcf4a6a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanFind); static_assert(!CanFind); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -68,11 +68,11 @@ void test() { test_find(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -83,6 +83,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp index 093c32e537ed35..1ceddb2f1c9d26 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -60,11 +60,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp index 18f9bc6dd32955..19991ca05fbc8a 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanLowerBound); static_assert(!CanLowerBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,11 @@ void test() { test_lower_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { bool transparent_used = false; @@ -89,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp index ab34de85103175..f25896e1229397 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp @@ -24,7 +24,7 @@ #include "min_allocator.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { using M = std::flat_set, KeyContainer>; @@ -61,11 +61,15 @@ void test() { } } +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); +} + int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp index 69ce2ae926a305..c9b519d2032193 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp @@ -35,7 +35,7 @@ static_assert(!CanUpperBound); static_assert(!CanUpperBound); template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; using M = std::flat_set; @@ -74,11 +74,12 @@ void test() { test_upper_bound(cm, "zzz", 5); } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); + { bool transparent_used = false; TransparentComparator c(transparent_used); @@ -88,6 +89,10 @@ int main(int, char**) { assert(it != m.end()); assert(transparent_used); } +} + +int main(int, char**) { + test(); return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h index 9fff262d84234e..2ee8b021337a06 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SUPPORT_flat_set_HELPERS_H -#define SUPPORT_flat_set_HELPERS_H +#ifndef SUPPORT_FLAT_SET_HELPERS_H +#define SUPPORT_FLAT_SET_HELPERS_H #include #include @@ -149,6 +149,19 @@ struct EmplaceUnsafeContainer : std::vector { throw 42; } + + template + auto insert_range(Args&&... args) + -> decltype(std::declval>().insert_range(std::forward(args)...)) { + if (this->size() > 1) { + auto it1 = this->begin(); + auto it2 = it1 + 1; + // messing up the container + std::iter_swap(it1, it2); + } + + throw 42; + } }; template @@ -291,4 +304,4 @@ class Moveable { bool moved() const { return int_ == -1; } }; -#endif // SUPPORT_flat_set_HELPERS_H +#endif // SUPPORT_FLAT_SET_HELPERS_H diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp index c4a9810016536b..faf746861df309 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp @@ -27,7 +27,10 @@ struct A { // Implement the operator< required in order to instantiate flat_set bool operator<(A const& L, A const& R) { return L.data < R.data; } +void test() { A a; } + int main(int, char**) { - A a; + test(); + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp index f6d08bb736d300..3e7aecee77fdd8 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/op_compare.pass.cpp @@ -31,7 +31,7 @@ #include "test_container_comparisons.h" template -void test() { +void test_one() { using Key = typename KeyContainer::value_type; { @@ -69,11 +69,11 @@ void test() { } } -int main(int, char**) { - test>(); - test>(); - test>(); - test>>(); +void test() { + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { using C = std::flat_set; @@ -101,5 +101,10 @@ int main(int, char**) { assert(s1 != s2); assert((s1 <=> s2) == std::partial_ordering::unordered); } +} + +int main(int, char**) { + test(); + return 0; } >From 6fa4b5763cccee5d1631d9239c12f33d5c656956 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 14:08:01 +0000 Subject: [PATCH 3/9] review --- .../flat.set/assert.sorted_unique.pass.cpp | 226 ++++++++++++++++++ .../assign_initializer_list.pass.cpp | 6 +- .../flat.set.cons/move_assign.pass.cpp | 67 ++++-- 3 files changed, 280 insertions(+), 19 deletions(-) create mode 100644 libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp diff --git a/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp new file mode 100644 index 00000000000000..62903af7f4e477 --- /dev/null +++ b/libcxx/test/libcxx/containers/container.adaptors/flat.set/assert.sorted_unique.pass.cpp @@ -0,0 +1,226 @@ +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: libcpp-hardening-mode=none +// REQUIRES: libcpp-hardening-mode=debug +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// + +// flat_set(container_type , const key_compare& __comp = key_compare()) +// flat_set(const container_type& , const _Allocator& ) +// flat_set(const container_type& , const key_compare&, const _Allocator& ) +// void replace(container_type&& ) +// + +#include +#include +#include +#include +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + using M = std::flat_set; + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}, std::less{}); }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, keys, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{2, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector keys{4, 2, 3}; + const std::allocator alloc{}; + const std::less comp{}; + M m(std::sorted_unique, keys, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v.begin(), v.end(), comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v.begin(), v.end(), alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + M m(std::sorted_unique, v, comp); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::less comp{}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, comp, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + const std::allocator alloc{}; + M m(std::sorted_unique, v, alloc); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + const std::vector v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v.begin(), v.end()); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{2, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::initializer_list v{4, 2, 3}; + M m; + m.insert(std::sorted_unique, v); + }()), + "Either the key container is not sorted or it contains duplicates"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{1, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + std::vector keys{2, 1, 3}; + M m; + m.replace(std::move(keys)); + }()), + "Either the key container is not sorted or it contains duplicates"); + + return 0; +} diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp index 7e948d7c5fe976..ad49b621490366 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp @@ -30,14 +30,16 @@ void test_one() { { M m = {8, 10}; assert(m.size() == 2); - m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + std::same_as decltype(auto) r = m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5}; + assert(&r == &m); int expected[] = {1, 2, 3, 4, 5, 6}; assert(std::ranges::equal(m, expected)); } { M m = {10, 8}; assert(m.size() == 2); - m = {3}; + std::same_as decltype(auto) r = m = {3}; + assert(&r == &m); int expected[] = {3}; assert(std::ranges::equal(m, expected)); } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp index e55a0516ed1bed..0e0ab0aa135f9f 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp @@ -55,6 +55,19 @@ struct MoveClears { auto operator<=>(const MoveClears&) const = default; }; +#if !defined(TEST_HAS_NO_EXCEPTIONS) +struct MoveAssignThrows : std::vector { + using std::vector::vector; + MoveAssignThrows& operator=(MoveAssignThrows&& other) { + push_back(0); + push_back(0); + other.push_back(0); + other.push_back(0); + throw 42; + } +}; +#endif // TEST_HAS_NO_EXCEPTIONS + void test_move_assign_clears() { // Preserves the class invariant for the moved-from flat_set. { @@ -101,6 +114,23 @@ void test_move_assign_clears() { check_invariant(m1); LIBCPP_ASSERT(m1.empty()); } +#if !defined(TEST_HAS_NO_EXCEPTIONS) + { + using M = std::flat_set, MoveAssignThrows>; + M m1 = {1, 2, 3}; + M m2 = {1, 2}; + try { + m2 = std::move(m1); + assert(false); + } catch (int e) { + assert(e == 42); + } + check_invariant(m1); + check_invariant(m2); + LIBCPP_ASSERT(m1.empty()); + LIBCPP_ASSERT(m2.empty()); + } +#endif // TEST_HAS_NO_EXCEPTIONS } struct MoveSensitiveComp { @@ -161,12 +191,13 @@ void test_move_assign_no_except() { void test() { { - using C = test_less; - using A1 = test_allocator; - using M = std::flat_set>; - M mo = M({1, 2, 3}, C(5), A1(7)); - M m = M({}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = test_allocator; + using M = std::flat_set>; + M mo = M({1, 2, 3}, C(5), A1(7)); + M m = M({}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{1, 2, 3})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -174,12 +205,13 @@ void test() { assert(mo.empty()); } { - using C = test_less; - using A1 = other_allocator; - using M = std::flat_set>; - M mo = M({4, 5}, C(5), A1(7)); - M m = M({1, 2, 3, 4}, C(3), A1(7)); - m = std::move(mo); + using C = test_less; + using A1 = other_allocator; + using M = std::flat_set>; + M mo = M({4, 5}, C(5), A1(7)); + M m = M({1, 2, 3, 4}, C(3), A1(7)); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{4, 5})); assert(m.key_comp() == C(5)); auto ks = std::move(m).extract(); @@ -187,11 +219,12 @@ void test() { assert(mo.empty()); } { - using A = min_allocator; - using M = std::flat_set, std::vector>; - M mo = M({5, 4, 3}, A()); - M m = M({4, 3, 2, 1}, A()); - m = std::move(mo); + using A = min_allocator; + using M = std::flat_set, std::vector>; + M mo = M({5, 4, 3}, A()); + M m = M({4, 3, 2, 1}, A()); + std::same_as decltype(auto) r = m = std::move(mo); + assert(&r == &m); assert((m == M{5, 4, 3})); auto ks = std::move(m).extract(); assert(ks.get_allocator() == A()); >From c65a37ea8012b92dc5575be91a1a18851a8caeaa Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 16:23:56 +0000 Subject: [PATCH 4/9] clang-format --- .../flat.set/flat.set.capacity/max_size.pass.cpp | 1 - .../flat.set.modifiers/insert_iter_cv.pass.cpp | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp index 0489d886257911..dde1f7092e5b18 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp @@ -25,7 +25,6 @@ #include "test_macros.h" void test() { - { using A1 = limited_allocator; using C = std::flat_set, std::vector>; diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp index d6791853e0debd..76b4d5f0eb7cc6 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp @@ -56,7 +56,6 @@ void test_one() { } void test() { - test_one>(); test_one>(); test_one>(); @@ -64,13 +63,13 @@ void test() { } void test_exception() { - auto insert_func = [](auto& m, auto key_arg) { - using FlatSet = std::decay_t; - using value_type = typename FlatSet::value_type; - const value_type p(key_arg); - m.insert(m.begin(), p); - }; - test_emplace_exception_guarantee(insert_func); + auto insert_func = [](auto& m, auto key_arg) { + using FlatSet = std::decay_t; + using value_type = typename FlatSet::value_type; + const value_type p(key_arg); + m.insert(m.begin(), p); + }; + test_emplace_exception_guarantee(insert_func); } int main(int, char**) { >From 61147247cfcf3fd4623587bddaa07a2c4783d2b6 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 16:59:41 +0000 Subject: [PATCH 5/9] CI --- libcxx/docs/ReleaseNotes/21.rst | 1 + libcxx/docs/Status/Cxx23Papers.csv | 2 +- libcxx/modules/std.compat.cppm.in | 3 - libcxx/modules/std.cppm.in | 4 +- libcxx/modules/std/flat_set.inc | 4 +- .../test/libcxx/transitive_includes/cxx03.csv | 8 ++ .../test/libcxx/transitive_includes/cxx11.csv | 8 ++ .../test/libcxx/transitive_includes/cxx14.csv | 8 ++ .../test/libcxx/transitive_includes/cxx17.csv | 8 ++ .../test/libcxx/transitive_includes/cxx20.csv | 8 ++ .../test/libcxx/transitive_includes/cxx23.csv | 15 +++- .../test/libcxx/transitive_includes/cxx26.csv | 14 ++++ .../flat_set.version.compile.pass.cpp | 80 +++++++++++++++++++ libcxx/utils/libcxx/header_information.py | 2 +- 14 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad3942..0c1029f50a6fe7 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -39,6 +39,7 @@ Implemented Papers ------------------ - N4258: Cleaning-up noexcept in the Library (`Github `__) +- P1222R4: A Standard ``flat_set`` is partially implemented and ``flat_set`` is provided (`Github `__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 264c5417a5c28b..bcd9c5c43a9c69 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -54,7 +54,7 @@ "`P0009R18 `__","mdspan: A Non-Owning Multidimensional Array Reference","2022-07 (Virtual)","|Complete|","18","" "`P0429R9 `__","A Standard ``flat_map``","2022-07 (Virtual)","|Complete|","20","" "`P1169R4 `__","``static operator()``","2022-07 (Virtual)","|Complete|","16","" -"`P1222R4 `__","A Standard ``flat_set``","2022-07 (Virtual)","","","" +"`P1222R4 `__","A Standard ``flat_set``","2022-07 (Virtual)","|In progress|","","" "`P1223R5 `__","``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()``","2022-07 (Virtual)","|Complete|","19","" "`P1467R9 `__","Extended ``floating-point`` types and standard names","2022-07 (Virtual)","","","" "`P1642R11 `__","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","2022-07 (Virtual)","","","" diff --git a/libcxx/modules/std.compat.cppm.in b/libcxx/modules/std.compat.cppm.in index 5cea1b75bfc170..95931447ccdc64 100644 --- a/libcxx/modules/std.compat.cppm.in +++ b/libcxx/modules/std.compat.cppm.in @@ -53,9 +53,6 @@ module; # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in index b9d00df70658d8..5c523691bff4e2 100644 --- a/libcxx/modules/std.cppm.in +++ b/libcxx/modules/std.cppm.in @@ -65,6 +65,7 @@ module; #include #include #include +#include #include #include #if _LIBCPP_HAS_LOCALIZATION @@ -162,9 +163,6 @@ module; # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std/flat_set.inc b/libcxx/modules/std/flat_set.inc index a86cc1eae02a62..3f2c6e09a0ebe4 100644 --- a/libcxx/modules/std/flat_set.inc +++ b/libcxx/modules/std/flat_set.inc @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// export namespace std { -#if 0 +#if _LIBCPP_STD_VER >= 23 // [flat.set], class template flat_­set using std::flat_set; @@ -19,7 +19,9 @@ export namespace std { // [flat.set.erasure], erasure for flat_­set using std::erase_if; +#endif // _LIBCPP_STD_VER >= 23 +#if 0 // [flat.multiset], class template flat_­multiset using std::flat_multiset; diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv index ec5db90597d927..c0031543e47bce 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -683,6 +683,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv index ec5db90597d927..c0031543e47bce 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -683,6 +683,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv index 95024df0590b84..c2eb5b44e8d7a7 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -701,6 +701,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv index a3518f7f62ecb9..332cb62f35b5f4 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -709,6 +709,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv index 6de95139279471..55c79acff5a8f9 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -705,6 +705,14 @@ flat_map initializer_list flat_map limits flat_map type_traits flat_map version +flat_set cmath +flat_set compare +flat_set cstddef +flat_set cstdint +flat_set initializer_list +flat_set limits +flat_set type_traits +flat_set version format algorithm format array format atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv index 17972b84537436..7da07a8b3749b2 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -345,6 +345,20 @@ flat_map optional flat_map stdexcept flat_map tuple flat_map version +flat_set cctype +flat_set climits +flat_set compare +flat_set cstdint +flat_set cstring +flat_set cwchar +flat_set cwctype +flat_set initializer_list +flat_set limits +flat_set optional +flat_set stdexcept +flat_set tuple +flat_set type_traits +flat_set version format array format cctype format cerrno @@ -556,7 +570,6 @@ istream ios istream iosfwd istream limits istream locale - istream ratio istream stdexcept istream streambuf diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv index 00ab78e61a4576..4c2782a4ce5cf9 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -345,6 +345,20 @@ flat_map optional flat_map stdexcept flat_map tuple flat_map version +flat_set cctype +flat_set climits +flat_set compare +flat_set cstdint +flat_set cstring +flat_set cwchar +flat_set cwctype +flat_set initializer_list +flat_set limits +flat_set optional +flat_set stdexcept +flat_set tuple +flat_set type_traits +flat_set version format array format cctype format cerrno diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp new file mode 100644 index 00000000000000..f9d0b0a6b4e4f6 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. +// +// clang-format off + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_flat_set 202207L [C++23] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined before c++23" +# endif + +#elif TEST_STD_VER == 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should be defined in c++23" +# endif +# if __cpp_lib_flat_set != 202207L +# error "__cpp_lib_flat_set should have the value 202207L in c++23" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#elif TEST_STD_VER > 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should be defined in c++26" +# endif +# if __cpp_lib_flat_set != 202207L +# error "__cpp_lib_flat_set should have the value 202207L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_flat_set +# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#endif // TEST_STD_VER > 23 + diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py index 9a723b61524cd5..9811b42d510ca3 100644 --- a/libcxx/utils/libcxx/header_information.py +++ b/libcxx/utils/libcxx/header_information.py @@ -164,7 +164,6 @@ def __hash__(self) -> int: # modules will fail to build if a header is added but this list is not updated. headers_not_available = list(map(Header, [ "debugging", - "flat_set", "generator", "hazard_pointer", "inplace_vector", @@ -261,6 +260,7 @@ def __hash__(self) -> int: "deque": ["compare", "initializer_list"], "filesystem": ["compare"], "flat_map": ["compare", "initializer_list"], + "flat_set": ["compare", "initializer_list"], "forward_list": ["compare", "initializer_list"], "ios": ["iosfwd"], "iostream": ["ios", "istream", "ostream", "streambuf"], >From a7583dad7798ec3f4259a2bcd4e851a85c7e04d6 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 18:05:17 +0000 Subject: [PATCH 6/9] deduction --- .../flat.set.cons/deduct.compile.pass.cpp | 14 +- .../flat.set/flat.set.cons/deduct.pass.cpp | 239 +++++++++--------- 2 files changed, 121 insertions(+), 132 deletions(-) diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp index 5db8c4ca722466..1161fe6e61c78e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp @@ -23,27 +23,21 @@ struct NotAnAllocator { }; template -concept CanDeductFlatSet = requires { std::flat_set{std::declval()...}; }; +concept CanDeductFlatSet = requires { std::flat_set(std::declval()...); }; -static_assert(CanDeductFlatSet, std::vector>); +static_assert(CanDeductFlatSet>); // cannot deduce Key and T from nothing static_assert(!CanDeductFlatSet<>); -// cannot deduce Key and T from just (KeyContainer), even if it's a container of pairs -static_assert(!CanDeductFlatSet>>); - -// cannot deduce Key and T from just (KeyContainer, Allocator) -static_assert(!CanDeductFlatSet, std::allocator>>); - // cannot deduce Key and T from just (Compare) static_assert(!CanDeductFlatSet>); // cannot deduce Key and T from just (Compare, Allocator) -static_assert(!CanDeductFlatSet, std::allocator>); +static_assert(!CanDeductFlatSet, std::allocator>); // cannot deduce Key and T from just (Allocator) -static_assert(!CanDeductFlatSet>); +static_assert(!CanDeductFlatSet>); // cannot convert from some arbitrary unrelated type static_assert(!CanDeductFlatSet); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp index 607fe0d1a9713a..491c77d3737af1 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp @@ -116,8 +116,8 @@ void test_containers_compare() { } void test_iter_iter() { - const int arr[] = {1, 2, 1, INT_MAX, 3}; - const int sorted_arr[] = {1, 2, 3, INT_MAX}; + int arr[] = {1, 2, 1, INT_MAX, 3}; + int sorted_arr[] = {1, 2, 3, INT_MAX}; const int arrc[] = {1, 2, 1, INT_MAX, 3}; const int sorted_arrc[] = {1, 2, 3, INT_MAX}; { @@ -154,6 +154,12 @@ void test_iter_iter() { std::flat_set m(mo.cbegin(), mo.cend()); ASSERT_SAME_TYPE(decltype(m), decltype(mo)); } + { + int source[3] = {1, 2, 3}; + std::flat_set s(source, source + 3); + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 3); + } { // This does not deduce to flat_set(InputIterator, InputIterator) // But deduces to flat_set(initializer_list) @@ -171,140 +177,125 @@ void test_iter_iter() { } void test_iter_iter_compare() { - // const P arr[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // const PC arrc[] = {{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - // const PC sorted_arrc[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // using C = std::greater; - // { - // std::flat_set m(std::begin(arr), std::end(arr), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::begin(arrc), std::end(arrc), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set mo; - // std::flat_set m(mo.begin(), mo.end(), C()); - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // } - // { - // std::flat_set mo; - // std::flat_set m(mo.cbegin(), mo.cend(), C()); - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // } + int arr[] = {1, 2, 1, INT_MAX, 3}; + int sorted_arr[] = {INT_MAX, 3, 2, 1}; + const int arrc[] = {1, 2, 1, INT_MAX, 3}; + const int sorted_arrc[] = {INT_MAX, 3, 2, 1}; + using C = std::greater; + { + std::flat_set m(std::begin(arr), std::end(arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::begin(arrc), std::end(arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set mo; + std::flat_set m(mo.begin(), mo.end(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } + { + std::flat_set mo; + std::flat_set m(mo.cbegin(), mo.cend(), C()); + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + } } void test_initializer_list() { - // const P sorted_arr[] = {{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}; - // { - // std::flat_set m{std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}; - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, {std::pair{1, 1L}, {2, 2L}, {3, 1L}, {INT_MAX, 1L}}); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set s = {std::make_pair(1, 'a')}; // flat_set(initializer_list>) - // ASSERT_SAME_TYPE(decltype(s), std::flat_set); - // assert(s.size() == 1); - // } - // { - // using M = std::flat_set; - // M m; - // std::flat_set s = {std::make_pair(m, m)}; // flat_set(initializer_list>) - // ASSERT_SAME_TYPE(decltype(s), std::flat_set); - // assert(s.size() == 1); - // assert(s[m] == m); - // } + const int sorted_arr[] = {1, 2, 3, INT_MAX}; + { + std::flat_set m{1, 2, 1, INT_MAX, 3}; + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {1, 2, 3, INT_MAX}); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set s = {1}; + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } + { + using M = std::flat_set; + M m; + std::flat_set s{m, m}; // flat_set(initializer_list) + ASSERT_SAME_TYPE(decltype(s), std::flat_set); + assert(s.size() == 1); + } } void test_initializer_list_compare() { - // const P sorted_arr[] = {{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}; - // using C = std::greater; - // { - // std::flat_set m({std::pair{1, 1L}, {2, 2L}, {1, 1L}, {INT_MAX, 1L}, {3, 1L}}, C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } - // { - // std::flat_set m(std::sorted_unique, {std::pair{INT_MAX, 1L}, {3, 1L}, {2, 2L}, {1, 1L}}, C()); - - // ASSERT_SAME_TYPE(decltype(m), std::flat_set); - // assert(std::ranges::equal(m, sorted_arr)); - // } + const int sorted_arr[] = {INT_MAX, 3, 2, 1}; + using C = std::greater; + { + std::flat_set m({1, 2, 1, INT_MAX, 3}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } + { + std::flat_set m(std::sorted_unique, {INT_MAX, 3, 2, 1}, C()); + + ASSERT_SAME_TYPE(decltype(m), std::flat_set); + assert(std::ranges::equal(m, sorted_arr)); + } } void test_from_range() { - // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - // const std::pair expected[] = {{1, 1}, {2, 2}, {3, 5}, {INT_MAX, 4}}; - // { - // std::flat_set s(std::from_range, r); - // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - // assert(std::ranges::equal(s, expected)); - // } - // { - // std::flat_set s(std::from_range, r, test_allocator(0, 42)); - // ASSERT_SAME_TYPE( - // decltype(s), - // std::flat_set, - // std::vector>, - // std::vector>>); - // assert(std::ranges::equal(s, expected)); - // assert(s.keys().get_allocator().get_id() == 42); - // assert(s.values().get_allocator().get_id() == 42); - // } + std::list r = {1, 2, 1, INT_MAX, 3}; + const int expected[] = {1, 2, 3, INT_MAX}; + { + std::flat_set s(std::from_range, r); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, test_allocator(0, 42)); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(std::move(s).extract().get_allocator().get_id() == 42); + } } void test_from_range_compare() { - // std::list> r = {{1, 1}, {2, 2}, {1, 1}, {INT_MAX, 4}, {3, 5}}; - // const std::pair expected[] = {{INT_MAX, 4}, {3, 5}, {2, 2}, {1, 1}}; - // { - // std::flat_set s(std::from_range, r, std::greater()); - // ASSERT_SAME_TYPE(decltype(s), std::flat_set>); - // assert(std::ranges::equal(s, expected)); - // } - // { - // std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); - // ASSERT_SAME_TYPE( - // decltype(s), - // std::flat_set, - // std::vector>, - // std::vector>>); - // assert(std::ranges::equal(s, expected)); - // assert(s.keys().get_allocator().get_id() == 42); - // assert(s.values().get_allocator().get_id() == 42); - // } + std::list r = {1, 2, 1, INT_MAX, 3}; + const int expected[] = {INT_MAX, 3, 2, 1}; + { + std::flat_set s(std::from_range, r, std::greater()); + ASSERT_SAME_TYPE(decltype(s), std::flat_set>); + assert(std::ranges::equal(s, expected)); + } + { + std::flat_set s(std::from_range, r, std::greater(), test_allocator(0, 42)); + ASSERT_SAME_TYPE(decltype(s), std::flat_set, std::vector>>); + assert(std::ranges::equal(s, expected)); + assert(std::move(s).extract().get_allocator().get_id() == 42); + } } -int main(int, char**) { +void test() { // Each test function also tests the sorted_unique-prefixed and allocator-suffixed overloads. test_copy(); test_containers(); @@ -317,6 +308,10 @@ int main(int, char**) { test_from_range_compare(); AssociativeContainerDeductionGuidesSfinaeAway>(); +} + +int main(int, char**) { + test(); return 0; } >From 8e266130512ef5788ea87361fcd0b194b0ae850e Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 18:45:39 +0000 Subject: [PATCH 7/9] CI --- libcxx/include/__flat_set/flat_set.h | 4 ++-- libcxx/include/module.modulemap | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index 37e4c9f7c686b0..30fe1343e63ee9 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -838,8 +838,8 @@ template _LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) { auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); }); - auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& e) -> bool { - return static_cast(__pred(e)); + auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& __e) -> bool { + return static_cast(__pred(__e)); }); auto __res = __flat_set.__keys_.end() - __it; __flat_set.__keys_.erase(__it, __flat_set.__keys_.end()); diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index abc351d5923963..261362baeec5b8 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1268,6 +1268,7 @@ module std [system] { header "__flat_set/flat_set.h" export std.vector.vector export std.vector.fwd + export std.flat_map.sorted_unique } header "flat_set" >From 6476ae0d0059fc4519f0f3b769ef5cfcf9aa53ba Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 19:14:41 +0000 Subject: [PATCH 8/9] CI again --- libcxx/include/module.modulemap | 2 +- .../flat.set/flat.set.cons/default.pass.cpp | 1 - .../flat.set/flat.set.modifiers/insert_transparent.pass.cpp | 6 +++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 261362baeec5b8..3d9e9d42894410 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1268,8 +1268,8 @@ module std [system] { header "__flat_set/flat_set.h" export std.vector.vector export std.vector.fwd - export std.flat_map.sorted_unique } + module sorted_unique { header "__flat_map/sorted_unique.h" } header "flat_set" export * diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp index 292af96c61582f..5cbd557eb8562e 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp @@ -53,7 +53,6 @@ void test() { } { using A1 = explicit_allocator; - using A2 = explicit_allocator; { std::flat_set> m; assert(m.empty()); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp index d2ddf95aac2bb7..4fe71b1cb898f2 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -146,9 +146,9 @@ void test_exception() { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; struct T { - typename FlatSet::key_type key; - T(typename FlatSet::key_type key) : key(key) {} - operator typename FlatSet::value_type() const { return key; } + typename FlatSet::key_type key_; + T(typename FlatSet::key_type key) : key_(key) {} + operator typename FlatSet::value_type() const { return key_; } }; T t(key_arg); m.insert(t); >From 222949d870d0ca1d5e64d24270edac38af37d0d7 Mon Sep 17 00:00:00 2001 From: Hui Xie Date: Sun, 2 Feb 2025 19:57:08 +0000 Subject: [PATCH 9/9] CI again --- libcxx/include/module.modulemap | 6 +++++- .../flat.set/flat.set.modifiers/insert_transparent.pass.cpp | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 3d9e9d42894410..a7672878811b68 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1269,9 +1269,13 @@ module std [system] { export std.vector.vector export std.vector.fwd } - module sorted_unique { header "__flat_map/sorted_unique.h" } + module sorted_unique { + header "__flat_map/sorted_unique.h" + export * + } header "flat_set" + export std.flat_map.sorted_unique export * } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp index 4fe71b1cb898f2..3c7784cbedace2 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -159,9 +159,9 @@ void test_exception() { auto insert_func_iter = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; struct T { - typename FlatSet::key_type key; - T(typename FlatSet::key_type key) : key(key) {} - operator typename FlatSet::value_type() const { return key; } + typename FlatSet::key_type key_; + T(typename FlatSet::key_type key) : key_(key) {} + operator typename FlatSet::value_type() const { return key_; } }; T t(key_arg); m.insert(m.begin(), t); From libcxx-commits at lists.llvm.org Sun Feb 2 13:08:55 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Sun, 02 Feb 2025 13:08:55 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Don't try to wait on a thread that hasn't started in std::async (PR #125433) Message-ID: https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/125433 If the creation of a thread fails, this causes an idle loop that will never end because the thread wasn't started in the first place. Fixes #125428 >From 55040502388a163ea09248b2da818d8448122981 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Sun, 2 Feb 2025 22:07:04 +0100 Subject: [PATCH] [libc++] Don't try to wait on a thread that hasn't started in std::async --- libcxx/include/future | 6 ++- .../thread_create_failure.pass.cpp | 46 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp diff --git a/libcxx/include/future b/libcxx/include/future index db1f624244b8f7..514d4c3d633d6c 100644 --- a/libcxx/include/future +++ b/libcxx/include/future @@ -865,7 +865,8 @@ void __async_assoc_state<_Rp, _Fp>::__execute() { template void __async_assoc_state<_Rp, _Fp>::__on_zero_shared() _NOEXCEPT { - this->wait(); + if (base::__state_ & base::__constructed) + this->wait(); base::__on_zero_shared(); } @@ -902,7 +903,8 @@ void __async_assoc_state::__execute() { template void __async_assoc_state::__on_zero_shared() _NOEXCEPT { - this->wait(); + if (base::__state_ & base::__constructed) + this->wait(); base::__on_zero_shared(); } diff --git a/libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp b/libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp new file mode 100644 index 00000000000000..ac5db590dbd8d1 --- /dev/null +++ b/libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: no-threads + +// There is no way to limit the number of threads on windows +// UNSUPPORTED: msvc + +#include +#include +#include + +#if __has_include() +# include +# ifdef RLIMIT_NPROC +void force_thread_creation_failure() { + rlimit lim = {1, 1}; + setrlimit(RLIMIT_NPROC, &lim); +} +# else +# error "No known way to force only one thread being available" +# endif +#else +# error "No known way to force only one thread being available" +#endif + +int main() { + force_thread_creation_failure(); + + try { + auto fut = std::async(std::launch::async, [] { return 1; }); + assert(false); + } catch (const std::system_error&) { + } + + try { + auto fut = std::async(std::launch::async, [] { return; }); + assert(false); + } catch (const std::system_error&) { + } +} From libcxx-commits at lists.llvm.org Sun Feb 2 13:09:25 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Sun, 02 Feb 2025 13:09:25 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Don't try to wait on a thread that hasn't started in std::async (PR #125433) In-Reply-To: Message-ID: <679fdf05.170a0220.179f4.6070@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-libcxx Author: Nikolas Klauser (philnik777)
Changes If the creation of a thread fails, this causes an idle loop that will never end because the thread wasn't started in the first place. Fixes #125428 --- Full diff: https://github.com/llvm/llvm-project/pull/125433.diff 2 Files Affected: - (modified) libcxx/include/future (+4-2) - (added) libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp (+46) ``````````diff diff --git a/libcxx/include/future b/libcxx/include/future index db1f624244b8f77..514d4c3d633d6cf 100644 --- a/libcxx/include/future +++ b/libcxx/include/future @@ -865,7 +865,8 @@ void __async_assoc_state<_Rp, _Fp>::__execute() { template void __async_assoc_state<_Rp, _Fp>::__on_zero_shared() _NOEXCEPT { - this->wait(); + if (base::__state_ & base::__constructed) + this->wait(); base::__on_zero_shared(); } @@ -902,7 +903,8 @@ void __async_assoc_state::__execute() { template void __async_assoc_state::__on_zero_shared() _NOEXCEPT { - this->wait(); + if (base::__state_ & base::__constructed) + this->wait(); base::__on_zero_shared(); } diff --git a/libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp b/libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp new file mode 100644 index 000000000000000..ac5db590dbd8d1d --- /dev/null +++ b/libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: no-threads + +// There is no way to limit the number of threads on windows +// UNSUPPORTED: msvc + +#include +#include +#include + +#if __has_include() +# include +# ifdef RLIMIT_NPROC +void force_thread_creation_failure() { + rlimit lim = {1, 1}; + setrlimit(RLIMIT_NPROC, &lim); +} +# else +# error "No known way to force only one thread being available" +# endif +#else +# error "No known way to force only one thread being available" +#endif + +int main() { + force_thread_creation_failure(); + + try { + auto fut = std::async(std::launch::async, [] { return 1; }); + assert(false); + } catch (const std::system_error&) { + } + + try { + auto fut = std::async(std::launch::async, [] { return; }); + assert(false); + } catch (const std::system_error&) { + } +} ``````````
https://github.com/llvm/llvm-project/pull/125433 From libcxx-commits at lists.llvm.org Sun Feb 2 18:35:14 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Sun, 02 Feb 2025 18:35:14 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::move{, _backward} for vector::iterator (PR #121109) In-Reply-To: Message-ID: <67a02b62.a70a0220.17e8fc.68e2@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/121109 >From 0b1009b0b9e04e1f8a6e7f7af28b0a7afbc4764f Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Mon, 23 Dec 2024 15:34:15 -0500 Subject: [PATCH] Optimize ranges::move{,_backward} for vector::iterator --- libcxx/include/__algorithm/move.h | 10 ++ libcxx/include/__algorithm/move_backward.h | 10 ++ libcxx/include/__bit_reference | 16 --- .../test/benchmarks/algorithms/move.bench.cpp | 55 ++++++++ .../algorithms/move_backward.bench.cpp | 55 ++++++++ .../alg.move/move.pass.cpp | 53 ++++++-- .../alg.move/move_backward.pass.cpp | 60 ++++++--- .../alg.move/ranges.move.pass.cpp | 107 +++++++++++----- .../alg.move/ranges.move_backward.pass.cpp | 118 +++++++++++++----- 9 files changed, 374 insertions(+), 110 deletions(-) create mode 100644 libcxx/test/benchmarks/algorithms/move.bench.cpp create mode 100644 libcxx/test/benchmarks/algorithms/move_backward.bench.cpp diff --git a/libcxx/include/__algorithm/move.h b/libcxx/include/__algorithm/move.h index 6f3b0eb5d2927c2..a3320e9f1985d06 100644 --- a/libcxx/include/__algorithm/move.h +++ b/libcxx/include/__algorithm/move.h @@ -9,11 +9,13 @@ #ifndef _LIBCPP___ALGORITHM_MOVE_H #define _LIBCPP___ALGORITHM_MOVE_H +#include <__algorithm/copy.h> #include <__algorithm/copy_move_common.h> #include <__algorithm/for_each_segment.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/min.h> #include <__config> +#include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> #include <__type_traits/common_type.h> @@ -98,6 +100,14 @@ struct __move_impl { } } + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> > + operator()(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + return std::__copy(__first, __last, __result); + } + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> diff --git a/libcxx/include/__algorithm/move_backward.h b/libcxx/include/__algorithm/move_backward.h index 24a8d9b24527a79..14482fee181147f 100644 --- a/libcxx/include/__algorithm/move_backward.h +++ b/libcxx/include/__algorithm/move_backward.h @@ -9,10 +9,12 @@ #ifndef _LIBCPP___ALGORITHM_MOVE_BACKWARD_H #define _LIBCPP___ALGORITHM_MOVE_BACKWARD_H +#include <__algorithm/copy_backward.h> #include <__algorithm/copy_move_common.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/min.h> #include <__config> +#include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> #include <__type_traits/common_type.h> @@ -107,6 +109,14 @@ struct __move_backward_impl { } } + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> > + operator()(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + return std::__copy_backward<_ClassicAlgPolicy>(__first, __last, __result); + } + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c398059..c4e007697154792 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -186,22 +186,6 @@ private: __mask_(__m) {} }; -// move - -template -inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> -move(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - return std::copy(__first, __last, __result); -} - -// move_backward - -template -inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> move_backward( - __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - return std::copy_backward(__first, __last, __result); -} - // swap_ranges template diff --git a/libcxx/test/benchmarks/algorithms/move.bench.cpp b/libcxx/test/benchmarks/algorithms/move.bench.cpp new file mode 100644 index 000000000000000..909c0c4f1b4c580 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/move.bench.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +static void bm_ranges_move_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto dst = aligned ? out.begin() : out.begin() + 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::move(in, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_move_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto beg = in.begin(); + auto end = in.end(); + auto dst = aligned ? out.begin() : out.begin() + 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::move(beg, end, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_ranges_move_vb_aligned(benchmark::State& state) { bm_ranges_move_vb(state, true); } +static void bm_ranges_move_vb_unaligned(benchmark::State& state) { bm_ranges_move_vb(state, false); } + +static void bm_move_vb_aligned(benchmark::State& state) { bm_move_vb(state, true); } +static void bm_move_vb_unaligned(benchmark::State& state) { bm_move_vb(state, false); } + +// Test std::ranges::move for vector::iterator +BENCHMARK(bm_ranges_move_vb_aligned)->Range(8, 1 << 16)->DenseRange(102400, 204800, 4096); +BENCHMARK(bm_ranges_move_vb_unaligned)->Range(8, 1 << 20); + +// Test std::move for vector::iterator +BENCHMARK(bm_move_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_move_vb_unaligned)->Range(8, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp new file mode 100644 index 000000000000000..48b1a776bf4dd9e --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +static void bm_ranges_move_backward_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto dst = aligned ? out.end() : out.end() - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::move_backward(in, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_move_backward(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto beg = in.begin(); + auto end = in.end(); + auto dst = aligned ? out.end() : out.end() - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::move_backward(beg, end, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_ranges_move_backward_vb_aligned(benchmark::State& state) { bm_ranges_move_backward_vb(state, true); } +static void bm_ranges_move_backward_vb_unaligned(benchmark::State& state) { bm_ranges_move_backward_vb(state, false); } + +static void bm_move_backward_vb_aligned(benchmark::State& state) { bm_move_backward(state, true); } +static void bm_move_backward_vb_unaligned(benchmark::State& state) { bm_move_backward(state, false); } + +// Test std::ranges::move_backward for vector::iterator +BENCHMARK(bm_ranges_move_backward_vb_aligned)->Range(8, 1 << 16)->DenseRange(102400, 204800, 4096); +BENCHMARK(bm_ranges_move_backward_vb_unaligned)->Range(8, 1 << 20); + +// Test std::move_backward for vector::iterator +BENCHMARK(bm_move_backward_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_move_backward_vb_unaligned)->Range(8, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp index b1ad6873bc5e5a8..8b414b061105f2a 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "MoveOnly.h" #include "test_iterators.h" @@ -45,15 +46,15 @@ struct Test { template TEST_CONSTEXPR_CXX20 void operator()() { const unsigned N = 1000; - int ia[N] = {}; + int ia[N] = {}; for (unsigned i = 0; i < N; ++i) - ia[i] = i; + ia[i] = i; int ib[N] = {0}; - OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib)); - assert(base(r) == ib+N); + OutIter r = std::move(InIter(ia), InIter(ia + N), OutIter(ib)); + assert(base(r) == ib + N); for (unsigned i = 0; i < N; ++i) - assert(ia[i] == ib[i]); + assert(ia[i] == ib[i]); } }; @@ -73,13 +74,13 @@ struct Test1 { const unsigned N = 100; std::unique_ptr ia[N]; for (unsigned i = 0; i < N; ++i) - ia[i].reset(new int(i)); + ia[i].reset(new int(i)); std::unique_ptr ib[N]; - OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib)); - assert(base(r) == ib+N); + OutIter r = std::move(InIter(ia), InIter(ia + N), OutIter(ib)); + assert(base(r) == ib + N); for (unsigned i = 0; i < N; ++i) - assert(*ib[i] == static_cast(i)); + assert(*ib[i] == static_cast(i)); } }; @@ -92,6 +93,26 @@ struct Test1OutIters { } }; +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move with aligned bytes + std::vector out(N); + std::move(in.begin(), in.end(), out.begin()); + assert(in == out); + } + { // Test move with unaligned bytes + std::vector out(N + 8); + std::move(in.begin(), in.end(), out.begin() + 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::cpp17_input_iterator_list(), TestOutIters()); if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED) @@ -118,7 +139,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When non-trivial { MoveOnly from[3] = {1, 2, 3}; - MoveOnly to[3] = {}; + MoveOnly to[3] = {}; std::move(std::begin(from), std::end(from), std::begin(to)); assert(to[0] == MoveOnly(1)); assert(to[1] == MoveOnly(2)); @@ -127,7 +148,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When trivial { TrivialMoveOnly from[3] = {1, 2, 3}; - TrivialMoveOnly to[3] = {}; + TrivialMoveOnly to[3] = {}; std::move(std::begin(from), std::end(from), std::begin(to)); assert(to[0] == TrivialMoveOnly(1)); assert(to[1] == TrivialMoveOnly(2)); @@ -135,6 +156,16 @@ TEST_CONSTEXPR_CXX20 bool test() { } } + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } + return true; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp index 61dea47b510716b..dfee9de2fa7687b 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "MoveOnly.h" #include "test_iterators.h" @@ -44,24 +45,22 @@ struct Test { template TEST_CONSTEXPR_CXX20 void operator()() { const unsigned N = 1000; - int ia[N] = {}; + int ia[N] = {}; for (unsigned i = 0; i < N; ++i) - ia[i] = i; + ia[i] = i; int ib[N] = {0}; - OutIter r = std::move_backward(InIter(ia), InIter(ia+N), OutIter(ib+N)); + OutIter r = std::move_backward(InIter(ia), InIter(ia + N), OutIter(ib + N)); assert(base(r) == ib); for (unsigned i = 0; i < N; ++i) - assert(ia[i] == ib[i]); + assert(ia[i] == ib[i]); } }; struct TestOutIters { template TEST_CONSTEXPR_CXX20 void operator()() { - types::for_each( - types::concatenate_t >(), - Test()); + types::for_each(types::concatenate_t >(), Test()); } }; @@ -72,24 +71,44 @@ struct Test1 { const unsigned N = 100; std::unique_ptr ia[N]; for (unsigned i = 0; i < N; ++i) - ia[i].reset(new int(i)); + ia[i].reset(new int(i)); std::unique_ptr ib[N]; - OutIter r = std::move_backward(InIter(ia), InIter(ia+N), OutIter(ib+N)); + OutIter r = std::move_backward(InIter(ia), InIter(ia + N), OutIter(ib + N)); assert(base(r) == ib); for (unsigned i = 0; i < N; ++i) - assert(*ib[i] == static_cast(i)); + assert(*ib[i] == static_cast(i)); } }; struct Test1OutIters { template TEST_CONSTEXPR_CXX23 void operator()() { - types::for_each(types::concatenate_t*> >(), - Test1()); + types::for_each( + types::concatenate_t*> >(), Test1()); } }; +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move_backward with aligned bytes + std::vector out(N); + std::move_backward(in.begin(), in.end(), out.end()); + assert(in == out); + } + { // Test move_backward with unaligned bytes + std::vector out(N + 8); + std::move_backward(in.begin(), in.end(), out.end() - 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::bidirectional_iterator_list(), TestOutIters()); if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED) @@ -117,7 +136,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When non-trivial { MoveOnly from[3] = {1, 2, 3}; - MoveOnly to[3] = {}; + MoveOnly to[3] = {}; std::move_backward(std::begin(from), std::end(from), std::end(to)); assert(to[0] == MoveOnly(1)); assert(to[1] == MoveOnly(2)); @@ -126,7 +145,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When trivial { TrivialMoveOnly from[3] = {1, 2, 3}; - TrivialMoveOnly to[3] = {}; + TrivialMoveOnly to[3] = {}; std::move_backward(std::begin(from), std::end(from), std::end(to)); assert(to[0] == TrivialMoveOnly(1)); assert(to[1] == TrivialMoveOnly(2)); @@ -134,11 +153,20 @@ TEST_CONSTEXPR_CXX20 bool test() { } } + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } + return true; } -int main(int, char**) -{ +int main(int, char**) { test(); #if TEST_STD_VER >= 20 static_assert(test()); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp index a0d1473360a14e8..664631aea826b14 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp @@ -31,6 +31,7 @@ #include "almost_satisfies_types.h" #include "MoveOnly.h" #include "test_iterators.h" +#include "test_macros.h" template > concept HasMoveIt = requires(In in, Sent sent, Out out) { std::ranges::move(in, sent, out); }; @@ -65,7 +66,7 @@ constexpr void test(std::array in) { { std::array out; std::same_as> decltype(auto) ret = - std::ranges::move(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); + std::ranges::move(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data() + out.size()); @@ -73,8 +74,7 @@ constexpr void test(std::array in) { { std::array out; auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); - std::same_as> decltype(auto) ret = - std::ranges::move(range, Out(out.data())); + std::same_as> decltype(auto) ret = std::ranges::move(range, Out(out.data())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data() + out.size()); @@ -84,16 +84,16 @@ constexpr void test(std::array in) { template constexpr void test_containers() { { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); std::same_as> auto ret = - std::ranges::move(In(in.begin()), Sent(In(in.end())), Out(out.begin())); + std::ranges::move(In(in.begin()), Sent(In(in.end())), Out(out.begin())); assert(std::ranges::equal(in, out)); assert(base(ret.in) == in.end()); assert(base(ret.out) == out.end()); } { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); auto range = std::ranges::subrange(In(in.begin()), Sent(In(in.end()))); std::same_as> auto ret = std::ranges::move(range, Out(out.begin())); @@ -165,22 +165,51 @@ constexpr void test_proxy_in_iterators() { } struct IteratorWithMoveIter { - using value_type = int; - using difference_type = int; + using value_type = int; + using difference_type = int; explicit IteratorWithMoveIter() = default; int* ptr; constexpr IteratorWithMoveIter(int* ptr_) : ptr(ptr_) {} constexpr int& operator*() const; // iterator with iter_move should not be dereferenced - constexpr IteratorWithMoveIter& operator++() { ++ptr; return *this; } - constexpr IteratorWithMoveIter operator++(int) { auto ret = *this; ++*this; return ret; } + constexpr IteratorWithMoveIter& operator++() { + ++ptr; + return *this; + } + constexpr IteratorWithMoveIter operator++(int) { + auto ret = *this; + ++*this; + return ret; + } friend constexpr int iter_move(const IteratorWithMoveIter&) { return 42; } constexpr bool operator==(const IteratorWithMoveIter& other) const = default; }; +#if TEST_STD_VER >= 23 +constexpr bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move with aligned bytes + std::vector out(N); + std::ranges::move(in, out.begin()); + assert(in == out); + } + { // Test move with unaligned bytes + std::vector out(N + 8); + std::ranges::move(in, out.begin() + 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} +#endif + // cpp17_intput_iterator has a defaulted template argument template using Cpp17InIter = cpp17_input_iterator; @@ -267,13 +296,13 @@ constexpr bool test() { { // check that ranges::dangling is returned std::array out; std::same_as> decltype(auto) ret = - std::ranges::move(std::array {1, 2, 3, 4}, out.data()); + std::ranges::move(std::array{1, 2, 3, 4}, out.data()); assert(ret.out == out.data() + 4); assert((out == std::array{1, 2, 3, 4})); } { // check that an iterator is returned with a borrowing range - std::array in {1, 2, 3, 4}; + std::array in{1, 2, 3, 4}; std::array out; std::same_as::iterator, int*>> decltype(auto) ret = std::ranges::move(std::views::all(in), out.data()); @@ -284,8 +313,8 @@ constexpr bool test() { { // check that every element is moved exactly once struct MoveOnce { - bool moved = false; - constexpr MoveOnce() = default; + bool moved = false; + constexpr MoveOnce() = default; constexpr MoveOnce(const MoveOnce& other) = delete; constexpr MoveOnce& operator=(MoveOnce&& other) { assert(!other.moved); @@ -294,16 +323,16 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move(in.begin(), in.end(), out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; })); } { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move(in, out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); @@ -314,8 +343,8 @@ constexpr bool test() { { // check that the range is moved forwards struct OnlyForwardsMovable { OnlyForwardsMovable* next = nullptr; - bool canMove = false; - OnlyForwardsMovable() = default; + bool canMove = false; + OnlyForwardsMovable() = default; constexpr OnlyForwardsMovable& operator=(OnlyForwardsMovable&&) { assert(canMove); if (next != nullptr) @@ -324,12 +353,12 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; - out[0].next = &out[1]; - out[1].next = &out[2]; + std::array in{}; + std::array out{}; + out[0].next = &out[1]; + out[1].next = &out[2]; out[0].canMove = true; - auto ret = std::ranges::move(in.begin(), in.end(), out.begin()); + auto ret = std::ranges::move(in.begin(), in.end(), out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); assert(out[0].canMove); @@ -337,12 +366,12 @@ constexpr bool test() { assert(out[2].canMove); } { - std::array in {}; - std::array out {}; - out[0].next = &out[1]; - out[1].next = &out[2]; + std::array in{}; + std::array out{}; + out[0].next = &out[1]; + out[1].next = &out[2]; out[0].canMove = true; - auto ret = std::ranges::move(in, out.begin()); + auto ret = std::ranges::move(in, out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); assert(out[0].canMove); @@ -358,19 +387,31 @@ constexpr bool test() { auto ret = std::ranges::move(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4), b.data()); assert(ret.in == a + 4); assert(ret.out == b.data() + 4); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } { int a[] = {1, 2, 3, 4}; std::array b; auto range = std::ranges::subrange(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4)); - auto ret = std::ranges::move(range, b.data()); + auto ret = std::ranges::move(range, b.data()); assert(ret.in == a + 4); assert(ret.out == b.data() + 4); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } } +#if TEST_STD_VER >= 23 + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } +#endif + return true; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp index 47cf178636ad130..a12ea8665f79343 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp @@ -31,6 +31,7 @@ #include "almost_satisfies_types.h" #include "MoveOnly.h" #include "test_iterators.h" +#include "test_macros.h" template > concept HasMoveBackwardIt = requires(In in, Sent sent, Out out) { std::ranges::move_backward(in, sent, out); }; @@ -65,7 +66,7 @@ constexpr void test(std::array in) { { std::array out; std::same_as> decltype(auto) ret = - std::ranges::move_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size())); + std::ranges::move_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data()); @@ -92,16 +93,16 @@ constexpr void test_iterators() { template constexpr void test_containers() { { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); std::same_as> auto ret = - std::ranges::move_backward(In(in.begin()), Sent(In(in.end())), Out(out.end())); + std::ranges::move_backward(In(in.begin()), Sent(In(in.end())), Out(out.end())); assert(std::ranges::equal(in, out)); assert(base(ret.in) == in.end()); assert(base(ret.out) == out.begin()); } { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); auto range = std::ranges::subrange(In(in.begin()), Sent(In(in.end()))); std::same_as> auto ret = std::ranges::move_backward(range, Out(out.end())); @@ -159,25 +160,61 @@ constexpr void test_proxy_in_iterators() { } struct IteratorWithMoveIter { - using value_type = int; - using difference_type = int; + using value_type = int; + using difference_type = int; explicit IteratorWithMoveIter() = default; int* ptr; constexpr IteratorWithMoveIter(int* ptr_) : ptr(ptr_) {} constexpr int& operator*() const; // iterator with iter_move should not be dereferenced - constexpr IteratorWithMoveIter& operator++() { ++ptr; return *this; } - constexpr IteratorWithMoveIter operator++(int) { auto ret = *this; ++*this; return ret; } + constexpr IteratorWithMoveIter& operator++() { + ++ptr; + return *this; + } + constexpr IteratorWithMoveIter operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - constexpr IteratorWithMoveIter& operator--() { --ptr; return *this; } - constexpr IteratorWithMoveIter operator--(int) { auto ret = *this; --*this; return ret; } + constexpr IteratorWithMoveIter& operator--() { + --ptr; + return *this; + } + constexpr IteratorWithMoveIter operator--(int) { + auto ret = *this; + --*this; + return ret; + } friend constexpr int iter_move(const IteratorWithMoveIter&) { return 42; } constexpr bool operator==(const IteratorWithMoveIter& other) const = default; }; +#if TEST_STD_VER >= 23 +constexpr bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move_backward with aligned bytes + std::vector out(N); + std::ranges::move_backward(in, out.end()); + assert(in == out); + } + { // Test move_backward with unaligned bytes + std::vector out(N + 8); + std::ranges::move_backward(in, out.end() - 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} +#endif + constexpr bool test() { test_in_iterators(); test_in_iterators(); @@ -243,7 +280,8 @@ constexpr bool test() { MoveOnly b[3]; ProxyRange proxyA{a}; ProxyRange proxyB{b}; - std::ranges::move_backward(std::begin(proxyA), std::end(proxyA), std::ranges::next(proxyB.begin(), std::end(proxyB))); + std::ranges::move_backward( + std::begin(proxyA), std::end(proxyA), std::ranges::next(proxyB.begin(), std::end(proxyB))); assert(b[0].get() == 1); assert(b[1].get() == 2); assert(b[2].get() == 3); @@ -253,13 +291,13 @@ constexpr bool test() { { // check that ranges::dangling is returned std::array out; std::same_as> auto ret = - std::ranges::move_backward(std::array {1, 2, 3, 4}, out.data() + out.size()); + std::ranges::move_backward(std::array{1, 2, 3, 4}, out.data() + out.size()); assert(ret.out == out.data()); assert((out == std::array{1, 2, 3, 4})); } { // check that an iterator is returned with a borrowing range - std::array in {1, 2, 3, 4}; + std::array in{1, 2, 3, 4}; std::array out; std::same_as::iterator, int*>> auto ret = std::ranges::move_backward(std::views::all(in), out.data() + out.size()); @@ -270,8 +308,8 @@ constexpr bool test() { { // check that every element is moved exactly once struct MoveOnce { - bool moved = false; - constexpr MoveOnce() = default; + bool moved = false; + constexpr MoveOnce() = default; constexpr MoveOnce(const MoveOnce& other) = delete; constexpr MoveOnce& operator=(const MoveOnce& other) { assert(!other.moved); @@ -280,16 +318,16 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move_backward(in.begin(), in.end(), out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; })); } { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move_backward(in, out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); @@ -300,8 +338,8 @@ constexpr bool test() { { // check that the range is moved backwards struct OnlyBackwardsMovable { OnlyBackwardsMovable* next = nullptr; - bool canMove = false; - OnlyBackwardsMovable() = default; + bool canMove = false; + OnlyBackwardsMovable() = default; constexpr OnlyBackwardsMovable& operator=(const OnlyBackwardsMovable&) { assert(canMove); if (next != nullptr) @@ -310,12 +348,12 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; - out[1].next = &out[0]; - out[2].next = &out[1]; + std::array in{}; + std::array out{}; + out[1].next = &out[0]; + out[2].next = &out[1]; out[2].canMove = true; - auto ret = std::ranges::move_backward(in, out.end()); + auto ret = std::ranges::move_backward(in, out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(out[0].canMove); @@ -323,12 +361,12 @@ constexpr bool test() { assert(out[2].canMove); } { - std::array in {}; - std::array out {}; - out[1].next = &out[0]; - out[2].next = &out[1]; + std::array in{}; + std::array out{}; + out[1].next = &out[0]; + out[2].next = &out[1]; out[2].canMove = true; - auto ret = std::ranges::move_backward(in.begin(), in.end(), out.end()); + auto ret = std::ranges::move_backward(in.begin(), in.end(), out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(out[0].canMove); @@ -344,19 +382,31 @@ constexpr bool test() { auto ret = std::ranges::move_backward(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4), b.data() + b.size()); assert(ret.in == a + 4); assert(ret.out == b.data()); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } { int a[] = {1, 2, 3, 4}; std::array b; auto range = std::ranges::subrange(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4)); - auto ret = std::ranges::move_backward(range, b.data() + b.size()); + auto ret = std::ranges::move_backward(range, b.data() + b.size()); assert(ret.in == a + 4); assert(ret.out == b.data()); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } } +#if TEST_STD_VER >= 23 + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } +#endif + return true; } From libcxx-commits at lists.llvm.org Sun Feb 2 20:30:21 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Sun, 02 Feb 2025 20:30:21 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::move{, _backward} for vector::iterator (PR #121109) In-Reply-To: Message-ID: <67a0465d.170a0220.1561a4.370f@mx.google.com> https://github.com/winner245 edited https://github.com/llvm/llvm-project/pull/121109 From libcxx-commits at lists.llvm.org Sun Feb 2 20:43:39 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Sun, 02 Feb 2025 20:43:39 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::move{, _backward} for vector::iterator (PR #121109) In-Reply-To: Message-ID: <67a0497b.170a0220.2328d1.5094@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/121109 >From 3200fa48c60337b1a23ec98aac68d37af4ea0e29 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Mon, 23 Dec 2024 15:34:15 -0500 Subject: [PATCH] Optimize ranges::move{,_backward} for vector::iterator --- libcxx/include/__algorithm/move.h | 10 ++ libcxx/include/__algorithm/move_backward.h | 10 ++ libcxx/include/__bit_reference | 16 --- .../test/benchmarks/algorithms/move.bench.cpp | 55 ++++++++ .../algorithms/move_backward.bench.cpp | 55 ++++++++ .../alg.move/move.pass.cpp | 53 ++++++-- .../alg.move/move_backward.pass.cpp | 60 ++++++--- .../alg.move/ranges.move.pass.cpp | 107 +++++++++++----- .../alg.move/ranges.move_backward.pass.cpp | 118 +++++++++++++----- 9 files changed, 374 insertions(+), 110 deletions(-) create mode 100644 libcxx/test/benchmarks/algorithms/move.bench.cpp create mode 100644 libcxx/test/benchmarks/algorithms/move_backward.bench.cpp diff --git a/libcxx/include/__algorithm/move.h b/libcxx/include/__algorithm/move.h index 6f3b0eb5d2927c..a3320e9f1985d0 100644 --- a/libcxx/include/__algorithm/move.h +++ b/libcxx/include/__algorithm/move.h @@ -9,11 +9,13 @@ #ifndef _LIBCPP___ALGORITHM_MOVE_H #define _LIBCPP___ALGORITHM_MOVE_H +#include <__algorithm/copy.h> #include <__algorithm/copy_move_common.h> #include <__algorithm/for_each_segment.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/min.h> #include <__config> +#include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> #include <__type_traits/common_type.h> @@ -98,6 +100,14 @@ struct __move_impl { } } + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> > + operator()(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + return std::__copy(__first, __last, __result); + } + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> diff --git a/libcxx/include/__algorithm/move_backward.h b/libcxx/include/__algorithm/move_backward.h index 24a8d9b24527a7..14482fee181147 100644 --- a/libcxx/include/__algorithm/move_backward.h +++ b/libcxx/include/__algorithm/move_backward.h @@ -9,10 +9,12 @@ #ifndef _LIBCPP___ALGORITHM_MOVE_BACKWARD_H #define _LIBCPP___ALGORITHM_MOVE_BACKWARD_H +#include <__algorithm/copy_backward.h> #include <__algorithm/copy_move_common.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/min.h> #include <__config> +#include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> #include <__type_traits/common_type.h> @@ -107,6 +109,14 @@ struct __move_backward_impl { } } + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> > + operator()(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + return std::__copy_backward<_ClassicAlgPolicy>(__first, __last, __result); + } + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c39805..c4e00769715479 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -186,22 +186,6 @@ private: __mask_(__m) {} }; -// move - -template -inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> -move(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - return std::copy(__first, __last, __result); -} - -// move_backward - -template -inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> move_backward( - __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - return std::copy_backward(__first, __last, __result); -} - // swap_ranges template diff --git a/libcxx/test/benchmarks/algorithms/move.bench.cpp b/libcxx/test/benchmarks/algorithms/move.bench.cpp new file mode 100644 index 00000000000000..909c0c4f1b4c58 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/move.bench.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +static void bm_ranges_move_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto dst = aligned ? out.begin() : out.begin() + 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::move(in, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_move_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto beg = in.begin(); + auto end = in.end(); + auto dst = aligned ? out.begin() : out.begin() + 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::move(beg, end, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_ranges_move_vb_aligned(benchmark::State& state) { bm_ranges_move_vb(state, true); } +static void bm_ranges_move_vb_unaligned(benchmark::State& state) { bm_ranges_move_vb(state, false); } + +static void bm_move_vb_aligned(benchmark::State& state) { bm_move_vb(state, true); } +static void bm_move_vb_unaligned(benchmark::State& state) { bm_move_vb(state, false); } + +// Test std::ranges::move for vector::iterator +BENCHMARK(bm_ranges_move_vb_aligned)->Range(8, 1 << 16)->DenseRange(102400, 204800, 4096); +BENCHMARK(bm_ranges_move_vb_unaligned)->Range(8, 1 << 20); + +// Test std::move for vector::iterator +BENCHMARK(bm_move_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_move_vb_unaligned)->Range(8, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp new file mode 100644 index 00000000000000..48b1a776bf4dd9 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +static void bm_ranges_move_backward_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto dst = aligned ? out.end() : out.end() - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::move_backward(in, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_move_backward(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto beg = in.begin(); + auto end = in.end(); + auto dst = aligned ? out.end() : out.end() - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::move_backward(beg, end, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_ranges_move_backward_vb_aligned(benchmark::State& state) { bm_ranges_move_backward_vb(state, true); } +static void bm_ranges_move_backward_vb_unaligned(benchmark::State& state) { bm_ranges_move_backward_vb(state, false); } + +static void bm_move_backward_vb_aligned(benchmark::State& state) { bm_move_backward(state, true); } +static void bm_move_backward_vb_unaligned(benchmark::State& state) { bm_move_backward(state, false); } + +// Test std::ranges::move_backward for vector::iterator +BENCHMARK(bm_ranges_move_backward_vb_aligned)->Range(8, 1 << 16)->DenseRange(102400, 204800, 4096); +BENCHMARK(bm_ranges_move_backward_vb_unaligned)->Range(8, 1 << 20); + +// Test std::move_backward for vector::iterator +BENCHMARK(bm_move_backward_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_move_backward_vb_unaligned)->Range(8, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp index b1ad6873bc5e5a..8b414b061105f2 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "MoveOnly.h" #include "test_iterators.h" @@ -45,15 +46,15 @@ struct Test { template TEST_CONSTEXPR_CXX20 void operator()() { const unsigned N = 1000; - int ia[N] = {}; + int ia[N] = {}; for (unsigned i = 0; i < N; ++i) - ia[i] = i; + ia[i] = i; int ib[N] = {0}; - OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib)); - assert(base(r) == ib+N); + OutIter r = std::move(InIter(ia), InIter(ia + N), OutIter(ib)); + assert(base(r) == ib + N); for (unsigned i = 0; i < N; ++i) - assert(ia[i] == ib[i]); + assert(ia[i] == ib[i]); } }; @@ -73,13 +74,13 @@ struct Test1 { const unsigned N = 100; std::unique_ptr ia[N]; for (unsigned i = 0; i < N; ++i) - ia[i].reset(new int(i)); + ia[i].reset(new int(i)); std::unique_ptr ib[N]; - OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib)); - assert(base(r) == ib+N); + OutIter r = std::move(InIter(ia), InIter(ia + N), OutIter(ib)); + assert(base(r) == ib + N); for (unsigned i = 0; i < N; ++i) - assert(*ib[i] == static_cast(i)); + assert(*ib[i] == static_cast(i)); } }; @@ -92,6 +93,26 @@ struct Test1OutIters { } }; +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move with aligned bytes + std::vector out(N); + std::move(in.begin(), in.end(), out.begin()); + assert(in == out); + } + { // Test move with unaligned bytes + std::vector out(N + 8); + std::move(in.begin(), in.end(), out.begin() + 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::cpp17_input_iterator_list(), TestOutIters()); if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED) @@ -118,7 +139,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When non-trivial { MoveOnly from[3] = {1, 2, 3}; - MoveOnly to[3] = {}; + MoveOnly to[3] = {}; std::move(std::begin(from), std::end(from), std::begin(to)); assert(to[0] == MoveOnly(1)); assert(to[1] == MoveOnly(2)); @@ -127,7 +148,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When trivial { TrivialMoveOnly from[3] = {1, 2, 3}; - TrivialMoveOnly to[3] = {}; + TrivialMoveOnly to[3] = {}; std::move(std::begin(from), std::end(from), std::begin(to)); assert(to[0] == TrivialMoveOnly(1)); assert(to[1] == TrivialMoveOnly(2)); @@ -135,6 +156,16 @@ TEST_CONSTEXPR_CXX20 bool test() { } } + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } + return true; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp index 61dea47b510716..dfee9de2fa7687 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "MoveOnly.h" #include "test_iterators.h" @@ -44,24 +45,22 @@ struct Test { template TEST_CONSTEXPR_CXX20 void operator()() { const unsigned N = 1000; - int ia[N] = {}; + int ia[N] = {}; for (unsigned i = 0; i < N; ++i) - ia[i] = i; + ia[i] = i; int ib[N] = {0}; - OutIter r = std::move_backward(InIter(ia), InIter(ia+N), OutIter(ib+N)); + OutIter r = std::move_backward(InIter(ia), InIter(ia + N), OutIter(ib + N)); assert(base(r) == ib); for (unsigned i = 0; i < N; ++i) - assert(ia[i] == ib[i]); + assert(ia[i] == ib[i]); } }; struct TestOutIters { template TEST_CONSTEXPR_CXX20 void operator()() { - types::for_each( - types::concatenate_t >(), - Test()); + types::for_each(types::concatenate_t >(), Test()); } }; @@ -72,24 +71,44 @@ struct Test1 { const unsigned N = 100; std::unique_ptr ia[N]; for (unsigned i = 0; i < N; ++i) - ia[i].reset(new int(i)); + ia[i].reset(new int(i)); std::unique_ptr ib[N]; - OutIter r = std::move_backward(InIter(ia), InIter(ia+N), OutIter(ib+N)); + OutIter r = std::move_backward(InIter(ia), InIter(ia + N), OutIter(ib + N)); assert(base(r) == ib); for (unsigned i = 0; i < N; ++i) - assert(*ib[i] == static_cast(i)); + assert(*ib[i] == static_cast(i)); } }; struct Test1OutIters { template TEST_CONSTEXPR_CXX23 void operator()() { - types::for_each(types::concatenate_t*> >(), - Test1()); + types::for_each( + types::concatenate_t*> >(), Test1()); } }; +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move_backward with aligned bytes + std::vector out(N); + std::move_backward(in.begin(), in.end(), out.end()); + assert(in == out); + } + { // Test move_backward with unaligned bytes + std::vector out(N + 8); + std::move_backward(in.begin(), in.end(), out.end() - 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::bidirectional_iterator_list(), TestOutIters()); if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED) @@ -117,7 +136,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When non-trivial { MoveOnly from[3] = {1, 2, 3}; - MoveOnly to[3] = {}; + MoveOnly to[3] = {}; std::move_backward(std::begin(from), std::end(from), std::end(to)); assert(to[0] == MoveOnly(1)); assert(to[1] == MoveOnly(2)); @@ -126,7 +145,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When trivial { TrivialMoveOnly from[3] = {1, 2, 3}; - TrivialMoveOnly to[3] = {}; + TrivialMoveOnly to[3] = {}; std::move_backward(std::begin(from), std::end(from), std::end(to)); assert(to[0] == TrivialMoveOnly(1)); assert(to[1] == TrivialMoveOnly(2)); @@ -134,11 +153,20 @@ TEST_CONSTEXPR_CXX20 bool test() { } } + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } + return true; } -int main(int, char**) -{ +int main(int, char**) { test(); #if TEST_STD_VER >= 20 static_assert(test()); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp index a0d1473360a14e..664631aea826b1 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp @@ -31,6 +31,7 @@ #include "almost_satisfies_types.h" #include "MoveOnly.h" #include "test_iterators.h" +#include "test_macros.h" template > concept HasMoveIt = requires(In in, Sent sent, Out out) { std::ranges::move(in, sent, out); }; @@ -65,7 +66,7 @@ constexpr void test(std::array in) { { std::array out; std::same_as> decltype(auto) ret = - std::ranges::move(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); + std::ranges::move(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data() + out.size()); @@ -73,8 +74,7 @@ constexpr void test(std::array in) { { std::array out; auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); - std::same_as> decltype(auto) ret = - std::ranges::move(range, Out(out.data())); + std::same_as> decltype(auto) ret = std::ranges::move(range, Out(out.data())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data() + out.size()); @@ -84,16 +84,16 @@ constexpr void test(std::array in) { template constexpr void test_containers() { { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); std::same_as> auto ret = - std::ranges::move(In(in.begin()), Sent(In(in.end())), Out(out.begin())); + std::ranges::move(In(in.begin()), Sent(In(in.end())), Out(out.begin())); assert(std::ranges::equal(in, out)); assert(base(ret.in) == in.end()); assert(base(ret.out) == out.end()); } { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); auto range = std::ranges::subrange(In(in.begin()), Sent(In(in.end()))); std::same_as> auto ret = std::ranges::move(range, Out(out.begin())); @@ -165,22 +165,51 @@ constexpr void test_proxy_in_iterators() { } struct IteratorWithMoveIter { - using value_type = int; - using difference_type = int; + using value_type = int; + using difference_type = int; explicit IteratorWithMoveIter() = default; int* ptr; constexpr IteratorWithMoveIter(int* ptr_) : ptr(ptr_) {} constexpr int& operator*() const; // iterator with iter_move should not be dereferenced - constexpr IteratorWithMoveIter& operator++() { ++ptr; return *this; } - constexpr IteratorWithMoveIter operator++(int) { auto ret = *this; ++*this; return ret; } + constexpr IteratorWithMoveIter& operator++() { + ++ptr; + return *this; + } + constexpr IteratorWithMoveIter operator++(int) { + auto ret = *this; + ++*this; + return ret; + } friend constexpr int iter_move(const IteratorWithMoveIter&) { return 42; } constexpr bool operator==(const IteratorWithMoveIter& other) const = default; }; +#if TEST_STD_VER >= 23 +constexpr bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move with aligned bytes + std::vector out(N); + std::ranges::move(in, out.begin()); + assert(in == out); + } + { // Test move with unaligned bytes + std::vector out(N + 8); + std::ranges::move(in, out.begin() + 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} +#endif + // cpp17_intput_iterator has a defaulted template argument template using Cpp17InIter = cpp17_input_iterator; @@ -267,13 +296,13 @@ constexpr bool test() { { // check that ranges::dangling is returned std::array out; std::same_as> decltype(auto) ret = - std::ranges::move(std::array {1, 2, 3, 4}, out.data()); + std::ranges::move(std::array{1, 2, 3, 4}, out.data()); assert(ret.out == out.data() + 4); assert((out == std::array{1, 2, 3, 4})); } { // check that an iterator is returned with a borrowing range - std::array in {1, 2, 3, 4}; + std::array in{1, 2, 3, 4}; std::array out; std::same_as::iterator, int*>> decltype(auto) ret = std::ranges::move(std::views::all(in), out.data()); @@ -284,8 +313,8 @@ constexpr bool test() { { // check that every element is moved exactly once struct MoveOnce { - bool moved = false; - constexpr MoveOnce() = default; + bool moved = false; + constexpr MoveOnce() = default; constexpr MoveOnce(const MoveOnce& other) = delete; constexpr MoveOnce& operator=(MoveOnce&& other) { assert(!other.moved); @@ -294,16 +323,16 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move(in.begin(), in.end(), out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; })); } { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move(in, out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); @@ -314,8 +343,8 @@ constexpr bool test() { { // check that the range is moved forwards struct OnlyForwardsMovable { OnlyForwardsMovable* next = nullptr; - bool canMove = false; - OnlyForwardsMovable() = default; + bool canMove = false; + OnlyForwardsMovable() = default; constexpr OnlyForwardsMovable& operator=(OnlyForwardsMovable&&) { assert(canMove); if (next != nullptr) @@ -324,12 +353,12 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; - out[0].next = &out[1]; - out[1].next = &out[2]; + std::array in{}; + std::array out{}; + out[0].next = &out[1]; + out[1].next = &out[2]; out[0].canMove = true; - auto ret = std::ranges::move(in.begin(), in.end(), out.begin()); + auto ret = std::ranges::move(in.begin(), in.end(), out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); assert(out[0].canMove); @@ -337,12 +366,12 @@ constexpr bool test() { assert(out[2].canMove); } { - std::array in {}; - std::array out {}; - out[0].next = &out[1]; - out[1].next = &out[2]; + std::array in{}; + std::array out{}; + out[0].next = &out[1]; + out[1].next = &out[2]; out[0].canMove = true; - auto ret = std::ranges::move(in, out.begin()); + auto ret = std::ranges::move(in, out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); assert(out[0].canMove); @@ -358,19 +387,31 @@ constexpr bool test() { auto ret = std::ranges::move(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4), b.data()); assert(ret.in == a + 4); assert(ret.out == b.data() + 4); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } { int a[] = {1, 2, 3, 4}; std::array b; auto range = std::ranges::subrange(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4)); - auto ret = std::ranges::move(range, b.data()); + auto ret = std::ranges::move(range, b.data()); assert(ret.in == a + 4); assert(ret.out == b.data() + 4); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } } +#if TEST_STD_VER >= 23 + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } +#endif + return true; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp index 47cf178636ad13..a12ea8665f7934 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp @@ -31,6 +31,7 @@ #include "almost_satisfies_types.h" #include "MoveOnly.h" #include "test_iterators.h" +#include "test_macros.h" template > concept HasMoveBackwardIt = requires(In in, Sent sent, Out out) { std::ranges::move_backward(in, sent, out); }; @@ -65,7 +66,7 @@ constexpr void test(std::array in) { { std::array out; std::same_as> decltype(auto) ret = - std::ranges::move_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size())); + std::ranges::move_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data()); @@ -92,16 +93,16 @@ constexpr void test_iterators() { template constexpr void test_containers() { { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); std::same_as> auto ret = - std::ranges::move_backward(In(in.begin()), Sent(In(in.end())), Out(out.end())); + std::ranges::move_backward(In(in.begin()), Sent(In(in.end())), Out(out.end())); assert(std::ranges::equal(in, out)); assert(base(ret.in) == in.end()); assert(base(ret.out) == out.begin()); } { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); auto range = std::ranges::subrange(In(in.begin()), Sent(In(in.end()))); std::same_as> auto ret = std::ranges::move_backward(range, Out(out.end())); @@ -159,25 +160,61 @@ constexpr void test_proxy_in_iterators() { } struct IteratorWithMoveIter { - using value_type = int; - using difference_type = int; + using value_type = int; + using difference_type = int; explicit IteratorWithMoveIter() = default; int* ptr; constexpr IteratorWithMoveIter(int* ptr_) : ptr(ptr_) {} constexpr int& operator*() const; // iterator with iter_move should not be dereferenced - constexpr IteratorWithMoveIter& operator++() { ++ptr; return *this; } - constexpr IteratorWithMoveIter operator++(int) { auto ret = *this; ++*this; return ret; } + constexpr IteratorWithMoveIter& operator++() { + ++ptr; + return *this; + } + constexpr IteratorWithMoveIter operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - constexpr IteratorWithMoveIter& operator--() { --ptr; return *this; } - constexpr IteratorWithMoveIter operator--(int) { auto ret = *this; --*this; return ret; } + constexpr IteratorWithMoveIter& operator--() { + --ptr; + return *this; + } + constexpr IteratorWithMoveIter operator--(int) { + auto ret = *this; + --*this; + return ret; + } friend constexpr int iter_move(const IteratorWithMoveIter&) { return 42; } constexpr bool operator==(const IteratorWithMoveIter& other) const = default; }; +#if TEST_STD_VER >= 23 +constexpr bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move_backward with aligned bytes + std::vector out(N); + std::ranges::move_backward(in, out.end()); + assert(in == out); + } + { // Test move_backward with unaligned bytes + std::vector out(N + 8); + std::ranges::move_backward(in, out.end() - 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} +#endif + constexpr bool test() { test_in_iterators(); test_in_iterators(); @@ -243,7 +280,8 @@ constexpr bool test() { MoveOnly b[3]; ProxyRange proxyA{a}; ProxyRange proxyB{b}; - std::ranges::move_backward(std::begin(proxyA), std::end(proxyA), std::ranges::next(proxyB.begin(), std::end(proxyB))); + std::ranges::move_backward( + std::begin(proxyA), std::end(proxyA), std::ranges::next(proxyB.begin(), std::end(proxyB))); assert(b[0].get() == 1); assert(b[1].get() == 2); assert(b[2].get() == 3); @@ -253,13 +291,13 @@ constexpr bool test() { { // check that ranges::dangling is returned std::array out; std::same_as> auto ret = - std::ranges::move_backward(std::array {1, 2, 3, 4}, out.data() + out.size()); + std::ranges::move_backward(std::array{1, 2, 3, 4}, out.data() + out.size()); assert(ret.out == out.data()); assert((out == std::array{1, 2, 3, 4})); } { // check that an iterator is returned with a borrowing range - std::array in {1, 2, 3, 4}; + std::array in{1, 2, 3, 4}; std::array out; std::same_as::iterator, int*>> auto ret = std::ranges::move_backward(std::views::all(in), out.data() + out.size()); @@ -270,8 +308,8 @@ constexpr bool test() { { // check that every element is moved exactly once struct MoveOnce { - bool moved = false; - constexpr MoveOnce() = default; + bool moved = false; + constexpr MoveOnce() = default; constexpr MoveOnce(const MoveOnce& other) = delete; constexpr MoveOnce& operator=(const MoveOnce& other) { assert(!other.moved); @@ -280,16 +318,16 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move_backward(in.begin(), in.end(), out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; })); } { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move_backward(in, out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); @@ -300,8 +338,8 @@ constexpr bool test() { { // check that the range is moved backwards struct OnlyBackwardsMovable { OnlyBackwardsMovable* next = nullptr; - bool canMove = false; - OnlyBackwardsMovable() = default; + bool canMove = false; + OnlyBackwardsMovable() = default; constexpr OnlyBackwardsMovable& operator=(const OnlyBackwardsMovable&) { assert(canMove); if (next != nullptr) @@ -310,12 +348,12 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; - out[1].next = &out[0]; - out[2].next = &out[1]; + std::array in{}; + std::array out{}; + out[1].next = &out[0]; + out[2].next = &out[1]; out[2].canMove = true; - auto ret = std::ranges::move_backward(in, out.end()); + auto ret = std::ranges::move_backward(in, out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(out[0].canMove); @@ -323,12 +361,12 @@ constexpr bool test() { assert(out[2].canMove); } { - std::array in {}; - std::array out {}; - out[1].next = &out[0]; - out[2].next = &out[1]; + std::array in{}; + std::array out{}; + out[1].next = &out[0]; + out[2].next = &out[1]; out[2].canMove = true; - auto ret = std::ranges::move_backward(in.begin(), in.end(), out.end()); + auto ret = std::ranges::move_backward(in.begin(), in.end(), out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(out[0].canMove); @@ -344,19 +382,31 @@ constexpr bool test() { auto ret = std::ranges::move_backward(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4), b.data() + b.size()); assert(ret.in == a + 4); assert(ret.out == b.data()); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } { int a[] = {1, 2, 3, 4}; std::array b; auto range = std::ranges::subrange(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4)); - auto ret = std::ranges::move_backward(range, b.data() + b.size()); + auto ret = std::ranges::move_backward(range, b.data() + b.size()); assert(ret.in == a + 4); assert(ret.out == b.data()); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } } +#if TEST_STD_VER >= 23 + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } +#endif + return true; } From libcxx-commits at lists.llvm.org Sun Feb 2 20:47:37 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Sun, 02 Feb 2025 20:47:37 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::move{, _backward} for vector::iterator (PR #121109) In-Reply-To: Message-ID: <67a04a69.170a0220.2d370a.3e70@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/121109 >From 926cc4121683c5c13e9f203ae546761a74ecf80a Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Mon, 23 Dec 2024 15:34:15 -0500 Subject: [PATCH] Optimize ranges::move{,_backward} for vector::iterator --- libcxx/docs/ReleaseNotes/21.rst | 5 +- libcxx/include/__algorithm/move.h | 10 ++ libcxx/include/__algorithm/move_backward.h | 10 ++ libcxx/include/__bit_reference | 16 --- .../test/benchmarks/algorithms/move.bench.cpp | 55 ++++++++ .../algorithms/move_backward.bench.cpp | 55 ++++++++ .../alg.move/move.pass.cpp | 53 ++++++-- .../alg.move/move_backward.pass.cpp | 60 ++++++--- .../alg.move/ranges.move.pass.cpp | 107 +++++++++++----- .../alg.move/ranges.move_backward.pass.cpp | 118 +++++++++++++----- 10 files changed, 376 insertions(+), 113 deletions(-) create mode 100644 libcxx/test/benchmarks/algorithms/move.bench.cpp create mode 100644 libcxx/test/benchmarks/algorithms/move_backward.bench.cpp diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad3942..9b3e120e4bfd64 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -43,9 +43,8 @@ Implemented Papers Improvements and New Features ----------------------------- -- The ``std::ranges::{copy, copy_n, copy_backward}`` algorithms have been optimized for ``std::vector::iterator``\s, - resulting in a performance improvement of up to 2000x. - +- The ``std::ranges::{copy, copy_n, copy_backward, move, move_backward}`` algorithms have been optimized for + ``std::vector::iterator``, resulting in a performance improvement of up to 2000x. Deprecations and Removals ------------------------- diff --git a/libcxx/include/__algorithm/move.h b/libcxx/include/__algorithm/move.h index 6f3b0eb5d2927c..a3320e9f1985d0 100644 --- a/libcxx/include/__algorithm/move.h +++ b/libcxx/include/__algorithm/move.h @@ -9,11 +9,13 @@ #ifndef _LIBCPP___ALGORITHM_MOVE_H #define _LIBCPP___ALGORITHM_MOVE_H +#include <__algorithm/copy.h> #include <__algorithm/copy_move_common.h> #include <__algorithm/for_each_segment.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/min.h> #include <__config> +#include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> #include <__type_traits/common_type.h> @@ -98,6 +100,14 @@ struct __move_impl { } } + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> > + operator()(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + return std::__copy(__first, __last, __result); + } + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> diff --git a/libcxx/include/__algorithm/move_backward.h b/libcxx/include/__algorithm/move_backward.h index 24a8d9b24527a7..14482fee181147 100644 --- a/libcxx/include/__algorithm/move_backward.h +++ b/libcxx/include/__algorithm/move_backward.h @@ -9,10 +9,12 @@ #ifndef _LIBCPP___ALGORITHM_MOVE_BACKWARD_H #define _LIBCPP___ALGORITHM_MOVE_BACKWARD_H +#include <__algorithm/copy_backward.h> #include <__algorithm/copy_move_common.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/min.h> #include <__config> +#include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> #include <__type_traits/common_type.h> @@ -107,6 +109,14 @@ struct __move_backward_impl { } } + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> > + operator()(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + return std::__copy_backward<_ClassicAlgPolicy>(__first, __last, __result); + } + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c39805..c4e00769715479 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -186,22 +186,6 @@ private: __mask_(__m) {} }; -// move - -template -inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> -move(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - return std::copy(__first, __last, __result); -} - -// move_backward - -template -inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> move_backward( - __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - return std::copy_backward(__first, __last, __result); -} - // swap_ranges template diff --git a/libcxx/test/benchmarks/algorithms/move.bench.cpp b/libcxx/test/benchmarks/algorithms/move.bench.cpp new file mode 100644 index 00000000000000..909c0c4f1b4c58 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/move.bench.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +static void bm_ranges_move_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto dst = aligned ? out.begin() : out.begin() + 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::move(in, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_move_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto beg = in.begin(); + auto end = in.end(); + auto dst = aligned ? out.begin() : out.begin() + 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::move(beg, end, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_ranges_move_vb_aligned(benchmark::State& state) { bm_ranges_move_vb(state, true); } +static void bm_ranges_move_vb_unaligned(benchmark::State& state) { bm_ranges_move_vb(state, false); } + +static void bm_move_vb_aligned(benchmark::State& state) { bm_move_vb(state, true); } +static void bm_move_vb_unaligned(benchmark::State& state) { bm_move_vb(state, false); } + +// Test std::ranges::move for vector::iterator +BENCHMARK(bm_ranges_move_vb_aligned)->Range(8, 1 << 16)->DenseRange(102400, 204800, 4096); +BENCHMARK(bm_ranges_move_vb_unaligned)->Range(8, 1 << 20); + +// Test std::move for vector::iterator +BENCHMARK(bm_move_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_move_vb_unaligned)->Range(8, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp new file mode 100644 index 00000000000000..48b1a776bf4dd9 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +static void bm_ranges_move_backward_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto dst = aligned ? out.end() : out.end() - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::move_backward(in, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_move_backward(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto beg = in.begin(); + auto end = in.end(); + auto dst = aligned ? out.end() : out.end() - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::move_backward(beg, end, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_ranges_move_backward_vb_aligned(benchmark::State& state) { bm_ranges_move_backward_vb(state, true); } +static void bm_ranges_move_backward_vb_unaligned(benchmark::State& state) { bm_ranges_move_backward_vb(state, false); } + +static void bm_move_backward_vb_aligned(benchmark::State& state) { bm_move_backward(state, true); } +static void bm_move_backward_vb_unaligned(benchmark::State& state) { bm_move_backward(state, false); } + +// Test std::ranges::move_backward for vector::iterator +BENCHMARK(bm_ranges_move_backward_vb_aligned)->Range(8, 1 << 16)->DenseRange(102400, 204800, 4096); +BENCHMARK(bm_ranges_move_backward_vb_unaligned)->Range(8, 1 << 20); + +// Test std::move_backward for vector::iterator +BENCHMARK(bm_move_backward_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_move_backward_vb_unaligned)->Range(8, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp index b1ad6873bc5e5a..8b414b061105f2 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "MoveOnly.h" #include "test_iterators.h" @@ -45,15 +46,15 @@ struct Test { template TEST_CONSTEXPR_CXX20 void operator()() { const unsigned N = 1000; - int ia[N] = {}; + int ia[N] = {}; for (unsigned i = 0; i < N; ++i) - ia[i] = i; + ia[i] = i; int ib[N] = {0}; - OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib)); - assert(base(r) == ib+N); + OutIter r = std::move(InIter(ia), InIter(ia + N), OutIter(ib)); + assert(base(r) == ib + N); for (unsigned i = 0; i < N; ++i) - assert(ia[i] == ib[i]); + assert(ia[i] == ib[i]); } }; @@ -73,13 +74,13 @@ struct Test1 { const unsigned N = 100; std::unique_ptr ia[N]; for (unsigned i = 0; i < N; ++i) - ia[i].reset(new int(i)); + ia[i].reset(new int(i)); std::unique_ptr ib[N]; - OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib)); - assert(base(r) == ib+N); + OutIter r = std::move(InIter(ia), InIter(ia + N), OutIter(ib)); + assert(base(r) == ib + N); for (unsigned i = 0; i < N; ++i) - assert(*ib[i] == static_cast(i)); + assert(*ib[i] == static_cast(i)); } }; @@ -92,6 +93,26 @@ struct Test1OutIters { } }; +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move with aligned bytes + std::vector out(N); + std::move(in.begin(), in.end(), out.begin()); + assert(in == out); + } + { // Test move with unaligned bytes + std::vector out(N + 8); + std::move(in.begin(), in.end(), out.begin() + 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::cpp17_input_iterator_list(), TestOutIters()); if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED) @@ -118,7 +139,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When non-trivial { MoveOnly from[3] = {1, 2, 3}; - MoveOnly to[3] = {}; + MoveOnly to[3] = {}; std::move(std::begin(from), std::end(from), std::begin(to)); assert(to[0] == MoveOnly(1)); assert(to[1] == MoveOnly(2)); @@ -127,7 +148,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When trivial { TrivialMoveOnly from[3] = {1, 2, 3}; - TrivialMoveOnly to[3] = {}; + TrivialMoveOnly to[3] = {}; std::move(std::begin(from), std::end(from), std::begin(to)); assert(to[0] == TrivialMoveOnly(1)); assert(to[1] == TrivialMoveOnly(2)); @@ -135,6 +156,16 @@ TEST_CONSTEXPR_CXX20 bool test() { } } + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } + return true; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp index 61dea47b510716..dfee9de2fa7687 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "MoveOnly.h" #include "test_iterators.h" @@ -44,24 +45,22 @@ struct Test { template TEST_CONSTEXPR_CXX20 void operator()() { const unsigned N = 1000; - int ia[N] = {}; + int ia[N] = {}; for (unsigned i = 0; i < N; ++i) - ia[i] = i; + ia[i] = i; int ib[N] = {0}; - OutIter r = std::move_backward(InIter(ia), InIter(ia+N), OutIter(ib+N)); + OutIter r = std::move_backward(InIter(ia), InIter(ia + N), OutIter(ib + N)); assert(base(r) == ib); for (unsigned i = 0; i < N; ++i) - assert(ia[i] == ib[i]); + assert(ia[i] == ib[i]); } }; struct TestOutIters { template TEST_CONSTEXPR_CXX20 void operator()() { - types::for_each( - types::concatenate_t >(), - Test()); + types::for_each(types::concatenate_t >(), Test()); } }; @@ -72,24 +71,44 @@ struct Test1 { const unsigned N = 100; std::unique_ptr ia[N]; for (unsigned i = 0; i < N; ++i) - ia[i].reset(new int(i)); + ia[i].reset(new int(i)); std::unique_ptr ib[N]; - OutIter r = std::move_backward(InIter(ia), InIter(ia+N), OutIter(ib+N)); + OutIter r = std::move_backward(InIter(ia), InIter(ia + N), OutIter(ib + N)); assert(base(r) == ib); for (unsigned i = 0; i < N; ++i) - assert(*ib[i] == static_cast(i)); + assert(*ib[i] == static_cast(i)); } }; struct Test1OutIters { template TEST_CONSTEXPR_CXX23 void operator()() { - types::for_each(types::concatenate_t*> >(), - Test1()); + types::for_each( + types::concatenate_t*> >(), Test1()); } }; +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move_backward with aligned bytes + std::vector out(N); + std::move_backward(in.begin(), in.end(), out.end()); + assert(in == out); + } + { // Test move_backward with unaligned bytes + std::vector out(N + 8); + std::move_backward(in.begin(), in.end(), out.end() - 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::bidirectional_iterator_list(), TestOutIters()); if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED) @@ -117,7 +136,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When non-trivial { MoveOnly from[3] = {1, 2, 3}; - MoveOnly to[3] = {}; + MoveOnly to[3] = {}; std::move_backward(std::begin(from), std::end(from), std::end(to)); assert(to[0] == MoveOnly(1)); assert(to[1] == MoveOnly(2)); @@ -126,7 +145,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When trivial { TrivialMoveOnly from[3] = {1, 2, 3}; - TrivialMoveOnly to[3] = {}; + TrivialMoveOnly to[3] = {}; std::move_backward(std::begin(from), std::end(from), std::end(to)); assert(to[0] == TrivialMoveOnly(1)); assert(to[1] == TrivialMoveOnly(2)); @@ -134,11 +153,20 @@ TEST_CONSTEXPR_CXX20 bool test() { } } + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } + return true; } -int main(int, char**) -{ +int main(int, char**) { test(); #if TEST_STD_VER >= 20 static_assert(test()); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp index a0d1473360a14e..664631aea826b1 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp @@ -31,6 +31,7 @@ #include "almost_satisfies_types.h" #include "MoveOnly.h" #include "test_iterators.h" +#include "test_macros.h" template > concept HasMoveIt = requires(In in, Sent sent, Out out) { std::ranges::move(in, sent, out); }; @@ -65,7 +66,7 @@ constexpr void test(std::array in) { { std::array out; std::same_as> decltype(auto) ret = - std::ranges::move(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); + std::ranges::move(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data() + out.size()); @@ -73,8 +74,7 @@ constexpr void test(std::array in) { { std::array out; auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); - std::same_as> decltype(auto) ret = - std::ranges::move(range, Out(out.data())); + std::same_as> decltype(auto) ret = std::ranges::move(range, Out(out.data())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data() + out.size()); @@ -84,16 +84,16 @@ constexpr void test(std::array in) { template constexpr void test_containers() { { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); std::same_as> auto ret = - std::ranges::move(In(in.begin()), Sent(In(in.end())), Out(out.begin())); + std::ranges::move(In(in.begin()), Sent(In(in.end())), Out(out.begin())); assert(std::ranges::equal(in, out)); assert(base(ret.in) == in.end()); assert(base(ret.out) == out.end()); } { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); auto range = std::ranges::subrange(In(in.begin()), Sent(In(in.end()))); std::same_as> auto ret = std::ranges::move(range, Out(out.begin())); @@ -165,22 +165,51 @@ constexpr void test_proxy_in_iterators() { } struct IteratorWithMoveIter { - using value_type = int; - using difference_type = int; + using value_type = int; + using difference_type = int; explicit IteratorWithMoveIter() = default; int* ptr; constexpr IteratorWithMoveIter(int* ptr_) : ptr(ptr_) {} constexpr int& operator*() const; // iterator with iter_move should not be dereferenced - constexpr IteratorWithMoveIter& operator++() { ++ptr; return *this; } - constexpr IteratorWithMoveIter operator++(int) { auto ret = *this; ++*this; return ret; } + constexpr IteratorWithMoveIter& operator++() { + ++ptr; + return *this; + } + constexpr IteratorWithMoveIter operator++(int) { + auto ret = *this; + ++*this; + return ret; + } friend constexpr int iter_move(const IteratorWithMoveIter&) { return 42; } constexpr bool operator==(const IteratorWithMoveIter& other) const = default; }; +#if TEST_STD_VER >= 23 +constexpr bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move with aligned bytes + std::vector out(N); + std::ranges::move(in, out.begin()); + assert(in == out); + } + { // Test move with unaligned bytes + std::vector out(N + 8); + std::ranges::move(in, out.begin() + 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} +#endif + // cpp17_intput_iterator has a defaulted template argument template using Cpp17InIter = cpp17_input_iterator; @@ -267,13 +296,13 @@ constexpr bool test() { { // check that ranges::dangling is returned std::array out; std::same_as> decltype(auto) ret = - std::ranges::move(std::array {1, 2, 3, 4}, out.data()); + std::ranges::move(std::array{1, 2, 3, 4}, out.data()); assert(ret.out == out.data() + 4); assert((out == std::array{1, 2, 3, 4})); } { // check that an iterator is returned with a borrowing range - std::array in {1, 2, 3, 4}; + std::array in{1, 2, 3, 4}; std::array out; std::same_as::iterator, int*>> decltype(auto) ret = std::ranges::move(std::views::all(in), out.data()); @@ -284,8 +313,8 @@ constexpr bool test() { { // check that every element is moved exactly once struct MoveOnce { - bool moved = false; - constexpr MoveOnce() = default; + bool moved = false; + constexpr MoveOnce() = default; constexpr MoveOnce(const MoveOnce& other) = delete; constexpr MoveOnce& operator=(MoveOnce&& other) { assert(!other.moved); @@ -294,16 +323,16 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move(in.begin(), in.end(), out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; })); } { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move(in, out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); @@ -314,8 +343,8 @@ constexpr bool test() { { // check that the range is moved forwards struct OnlyForwardsMovable { OnlyForwardsMovable* next = nullptr; - bool canMove = false; - OnlyForwardsMovable() = default; + bool canMove = false; + OnlyForwardsMovable() = default; constexpr OnlyForwardsMovable& operator=(OnlyForwardsMovable&&) { assert(canMove); if (next != nullptr) @@ -324,12 +353,12 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; - out[0].next = &out[1]; - out[1].next = &out[2]; + std::array in{}; + std::array out{}; + out[0].next = &out[1]; + out[1].next = &out[2]; out[0].canMove = true; - auto ret = std::ranges::move(in.begin(), in.end(), out.begin()); + auto ret = std::ranges::move(in.begin(), in.end(), out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); assert(out[0].canMove); @@ -337,12 +366,12 @@ constexpr bool test() { assert(out[2].canMove); } { - std::array in {}; - std::array out {}; - out[0].next = &out[1]; - out[1].next = &out[2]; + std::array in{}; + std::array out{}; + out[0].next = &out[1]; + out[1].next = &out[2]; out[0].canMove = true; - auto ret = std::ranges::move(in, out.begin()); + auto ret = std::ranges::move(in, out.begin()); assert(ret.in == in.end()); assert(ret.out == out.end()); assert(out[0].canMove); @@ -358,19 +387,31 @@ constexpr bool test() { auto ret = std::ranges::move(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4), b.data()); assert(ret.in == a + 4); assert(ret.out == b.data() + 4); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } { int a[] = {1, 2, 3, 4}; std::array b; auto range = std::ranges::subrange(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4)); - auto ret = std::ranges::move(range, b.data()); + auto ret = std::ranges::move(range, b.data()); assert(ret.in == a + 4); assert(ret.out == b.data() + 4); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } } +#if TEST_STD_VER >= 23 + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } +#endif + return true; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp index 47cf178636ad13..a12ea8665f7934 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp @@ -31,6 +31,7 @@ #include "almost_satisfies_types.h" #include "MoveOnly.h" #include "test_iterators.h" +#include "test_macros.h" template > concept HasMoveBackwardIt = requires(In in, Sent sent, Out out) { std::ranges::move_backward(in, sent, out); }; @@ -65,7 +66,7 @@ constexpr void test(std::array in) { { std::array out; std::same_as> decltype(auto) ret = - std::ranges::move_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size())); + std::ranges::move_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data()); @@ -92,16 +93,16 @@ constexpr void test_iterators() { template constexpr void test_containers() { { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); std::same_as> auto ret = - std::ranges::move_backward(In(in.begin()), Sent(In(in.end())), Out(out.end())); + std::ranges::move_backward(In(in.begin()), Sent(In(in.end())), Out(out.end())); assert(std::ranges::equal(in, out)); assert(base(ret.in) == in.end()); assert(base(ret.out) == out.begin()); } { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); auto range = std::ranges::subrange(In(in.begin()), Sent(In(in.end()))); std::same_as> auto ret = std::ranges::move_backward(range, Out(out.end())); @@ -159,25 +160,61 @@ constexpr void test_proxy_in_iterators() { } struct IteratorWithMoveIter { - using value_type = int; - using difference_type = int; + using value_type = int; + using difference_type = int; explicit IteratorWithMoveIter() = default; int* ptr; constexpr IteratorWithMoveIter(int* ptr_) : ptr(ptr_) {} constexpr int& operator*() const; // iterator with iter_move should not be dereferenced - constexpr IteratorWithMoveIter& operator++() { ++ptr; return *this; } - constexpr IteratorWithMoveIter operator++(int) { auto ret = *this; ++*this; return ret; } + constexpr IteratorWithMoveIter& operator++() { + ++ptr; + return *this; + } + constexpr IteratorWithMoveIter operator++(int) { + auto ret = *this; + ++*this; + return ret; + } - constexpr IteratorWithMoveIter& operator--() { --ptr; return *this; } - constexpr IteratorWithMoveIter operator--(int) { auto ret = *this; --*this; return ret; } + constexpr IteratorWithMoveIter& operator--() { + --ptr; + return *this; + } + constexpr IteratorWithMoveIter operator--(int) { + auto ret = *this; + --*this; + return ret; + } friend constexpr int iter_move(const IteratorWithMoveIter&) { return 42; } constexpr bool operator==(const IteratorWithMoveIter& other) const = default; }; +#if TEST_STD_VER >= 23 +constexpr bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move_backward with aligned bytes + std::vector out(N); + std::ranges::move_backward(in, out.end()); + assert(in == out); + } + { // Test move_backward with unaligned bytes + std::vector out(N + 8); + std::ranges::move_backward(in, out.end() - 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} +#endif + constexpr bool test() { test_in_iterators(); test_in_iterators(); @@ -243,7 +280,8 @@ constexpr bool test() { MoveOnly b[3]; ProxyRange proxyA{a}; ProxyRange proxyB{b}; - std::ranges::move_backward(std::begin(proxyA), std::end(proxyA), std::ranges::next(proxyB.begin(), std::end(proxyB))); + std::ranges::move_backward( + std::begin(proxyA), std::end(proxyA), std::ranges::next(proxyB.begin(), std::end(proxyB))); assert(b[0].get() == 1); assert(b[1].get() == 2); assert(b[2].get() == 3); @@ -253,13 +291,13 @@ constexpr bool test() { { // check that ranges::dangling is returned std::array out; std::same_as> auto ret = - std::ranges::move_backward(std::array {1, 2, 3, 4}, out.data() + out.size()); + std::ranges::move_backward(std::array{1, 2, 3, 4}, out.data() + out.size()); assert(ret.out == out.data()); assert((out == std::array{1, 2, 3, 4})); } { // check that an iterator is returned with a borrowing range - std::array in {1, 2, 3, 4}; + std::array in{1, 2, 3, 4}; std::array out; std::same_as::iterator, int*>> auto ret = std::ranges::move_backward(std::views::all(in), out.data() + out.size()); @@ -270,8 +308,8 @@ constexpr bool test() { { // check that every element is moved exactly once struct MoveOnce { - bool moved = false; - constexpr MoveOnce() = default; + bool moved = false; + constexpr MoveOnce() = default; constexpr MoveOnce(const MoveOnce& other) = delete; constexpr MoveOnce& operator=(const MoveOnce& other) { assert(!other.moved); @@ -280,16 +318,16 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move_backward(in.begin(), in.end(), out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; })); } { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::move_backward(in, out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); @@ -300,8 +338,8 @@ constexpr bool test() { { // check that the range is moved backwards struct OnlyBackwardsMovable { OnlyBackwardsMovable* next = nullptr; - bool canMove = false; - OnlyBackwardsMovable() = default; + bool canMove = false; + OnlyBackwardsMovable() = default; constexpr OnlyBackwardsMovable& operator=(const OnlyBackwardsMovable&) { assert(canMove); if (next != nullptr) @@ -310,12 +348,12 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; - out[1].next = &out[0]; - out[2].next = &out[1]; + std::array in{}; + std::array out{}; + out[1].next = &out[0]; + out[2].next = &out[1]; out[2].canMove = true; - auto ret = std::ranges::move_backward(in, out.end()); + auto ret = std::ranges::move_backward(in, out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(out[0].canMove); @@ -323,12 +361,12 @@ constexpr bool test() { assert(out[2].canMove); } { - std::array in {}; - std::array out {}; - out[1].next = &out[0]; - out[2].next = &out[1]; + std::array in{}; + std::array out{}; + out[1].next = &out[0]; + out[2].next = &out[1]; out[2].canMove = true; - auto ret = std::ranges::move_backward(in.begin(), in.end(), out.end()); + auto ret = std::ranges::move_backward(in.begin(), in.end(), out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(out[0].canMove); @@ -344,19 +382,31 @@ constexpr bool test() { auto ret = std::ranges::move_backward(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4), b.data() + b.size()); assert(ret.in == a + 4); assert(ret.out == b.data()); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } { int a[] = {1, 2, 3, 4}; std::array b; auto range = std::ranges::subrange(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4)); - auto ret = std::ranges::move_backward(range, b.data() + b.size()); + auto ret = std::ranges::move_backward(range, b.data() + b.size()); assert(ret.in == a + 4); assert(ret.out == b.data()); - assert((b == std::array {42, 42, 42, 42})); + assert((b == std::array{42, 42, 42, 42})); } } +#if TEST_STD_VER >= 23 + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } +#endif + return true; } From libcxx-commits at lists.llvm.org Mon Feb 3 01:58:44 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Mon, 03 Feb 2025 01:58:44 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Reduce std::conjunction overhead (PR #124259) In-Reply-To: Message-ID: <67a09354.170a0220.1ac22f.4960@mx.google.com> asmok-g wrote: Our internal assessment of the situation is that this exposes a bug in the compiler but it will need time to get to the bottom of it. In the meantime we suggest to revert the patch till the problem is known and fixed @philnik777 what do you think ? https://github.com/llvm/llvm-project/pull/124259 From libcxx-commits at lists.llvm.org Mon Feb 3 05:30:08 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 05:30:08 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Reduce std::conjunction overhead (PR #124259) In-Reply-To: Message-ID: <67a0c4e0.630a0220.a2a70.95d2@mx.google.com> philnik777 wrote: @asmok-g I'd really like to have a reproducer before reverting. https://github.com/llvm/llvm-project/pull/124259 From libcxx-commits at lists.llvm.org Mon Feb 3 06:33:36 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 06:33:36 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Support `constexpr` for `std::stable_sort` in radix sort branch (PR #125284) Message-ID: <67a0d3c0.630a0220.28c24a.e680@mx.google.com> =?utf-8?b?0JTQvNC40YLRgNC40Lkg0JjQtw=?=, =?utf-8?b?0JTQvNC40YLRgNC40Lkg0JjQtw=?Message-ID: In-Reply-To: ================ @@ -253,6 +253,12 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort( if constexpr (__allowed_radix_sort) { if (__len <= __buff_size && __len >= static_cast(__radix_sort_min_bound()) && __len <= static_cast(__radix_sort_max_bound())) { + for (auto* __p = __buff; __p < __buff + __buff_size; ++__p) { + std::__construct_at(__p, 0); + } + __destruct_n __d(__buff_size); + unique_ptr __h2(__buff, __d); ---------------- philnik777 wrote: This is all only required for `constexpr` support, right? I'm pretty sure you can drop the destruction, since the elements should always be trivial. For the construction, I think we don't need the zero and we should probably only do it during constant evaluation. https://github.com/llvm/llvm-project/pull/125284 From libcxx-commits at lists.llvm.org Mon Feb 3 07:13:02 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 07:13:02 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix basic_string not allowing max_size() elements to be stored (PR #125423) In-Reply-To: Message-ID: <67a0dcfe.170a0220.ec092.ccb2@mx.google.com> https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/125423 >From 50dea86a21c3f7c577be3c1500d49a7c6e450baf Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Sun, 2 Feb 2025 18:01:27 +0100 Subject: [PATCH] [libc++] Fix basic_string not allowing max_size() elements to be stored --- libcxx/include/string | 6 +-- .../string.capacity/max_size.pass.cpp | 20 ++++---- .../string.capacity/max_size.pass.cpp | 10 +++- .../string.capacity/resize_size.pass.cpp | 46 ++++++++++++------- libcxx/test/support/min_allocator.h | 28 +++++++++++ 5 files changed, 79 insertions(+), 31 deletions(-) diff --git a/libcxx/include/string b/libcxx/include/string index fdd8085106dcc60..892ae97518f719e 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -1305,10 +1305,10 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type max_size() const _NOEXCEPT { size_type __m = __alloc_traits::max_size(__alloc_); if (__m <= std::numeric_limits::max() / 2) { - return __m - __alignment; + return __m - __alignment - 1; } else { bool __uses_lsb = __endian_factor == 2; - return __uses_lsb ? __m - __alignment : (__m / 2) - __alignment; + return __uses_lsb ? __m - __alignment - 1 : (__m / 2) - __alignment - 1; } } @@ -2558,7 +2558,7 @@ _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Trait __throw_length_error(); pointer __old_p = __get_pointer(); size_type __cap = - __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; + __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms; auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1); pointer __p = __allocation.ptr; __begin_lifetime(__p, __allocation.count); diff --git a/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp index 726570beb6d1ae6..e097c70ec79a7c1 100644 --- a/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp +++ b/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp @@ -23,44 +23,44 @@ static const std::size_t alignment = 8; template TEST_CONSTEXPR_CXX20 void full_size() { std::string str; - assert(str.max_size() == std::numeric_limits::max() - alignment); + assert(str.max_size() == std::numeric_limits::max() - alignment - 1); #ifndef TEST_HAS_NO_CHAR8_T std::u8string u8str; - assert(u8str.max_size() == std::numeric_limits::max() - alignment); + assert(u8str.max_size() == std::numeric_limits::max() - alignment - 1); #endif #ifndef TEST_HAS_NO_WIDE_CHARACTERS std::wstring wstr; - assert(wstr.max_size() == std::numeric_limits::max() / sizeof(wchar_t) - alignment); + assert(wstr.max_size() == std::numeric_limits::max() / sizeof(wchar_t) - alignment - 1); #endif std::u16string u16str; std::u32string u32str; - assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment); - assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment); + assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); + assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment - 1); } template TEST_CONSTEXPR_CXX20 void half_size() { std::string str; - assert(str.max_size() == std::numeric_limits::max() / 2 - alignment); + assert(str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); #ifndef TEST_HAS_NO_CHAR8_T std::u8string u8str; - assert(u8str.max_size() == std::numeric_limits::max() / 2 - alignment); + assert(u8str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); #endif #ifndef TEST_HAS_NO_WIDE_CHARACTERS std::wstring wstr; assert(wstr.max_size() == - std::numeric_limits::max() / std::max(2ul, sizeof(wchar_t)) - alignment); + std::numeric_limits::max() / std::max(2ul, sizeof(wchar_t)) - alignment - 1); #endif std::u16string u16str; std::u32string u32str; - assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment); - assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment); + assert(u16str.max_size() == std::numeric_limits::max() / 2 - alignment - 1); + assert(u32str.max_size() == std::numeric_limits::max() / 4 - alignment - 1); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp index b9ffffc0993af89..ff38a59cb00e58e 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp @@ -53,7 +53,7 @@ TEST_CONSTEXPR_CXX20 void test_resize_max_size(const S& s) { } catch (const std::bad_alloc&) { return; } - assert(s.size() == sz); + assert(s2.size() == sz); } template @@ -91,8 +91,16 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator > >(); + test_string, tiny_size_allocator<64, char> > >(); #endif + { // Test resizing where we can assume that the allocation succeeds + std::basic_string, tiny_size_allocator<32, char> > str; + auto max_size = str.max_size(); + str.resize(max_size); + assert(str.size() == max_size); + } + return true; } diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp index 7cf4b7ca3b6efd6..91c15327c78beef 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp @@ -20,22 +20,10 @@ template TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, S expected) { - if (n <= s.max_size()) { - s.resize(n); - LIBCPP_ASSERT(s.__invariants()); - assert(s == expected); - LIBCPP_ASSERT(is_string_asan_correct(s)); - } -#ifndef TEST_HAS_NO_EXCEPTIONS - else if (!TEST_IS_CONSTANT_EVALUATED) { - try { - s.resize(n); - assert(false); - } catch (std::length_error&) { - assert(n > s.max_size()); - } - } -#endif + s.resize(n); + LIBCPP_ASSERT(s.__invariants()); + assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template @@ -56,7 +44,26 @@ TEST_CONSTEXPR_CXX20 void test_string() { test(S("12345678901234567890123456789012345678901234567890"), 60, S("12345678901234567890123456789012345678901234567890\0\0\0\0\0\0\0\0\0\0", 60)); - test(S(), S::npos, S("not going to happen")); +} + +template +TEST_CONSTEXPR_CXX20 void test_max_size() { +#ifndef TEST_HAS_NO_EXCEPTIONS + if (!TEST_IS_CONSTANT_EVALUATED) { + std::basic_string str; + try { + str.resize(std::string::npos); + assert(false); + } catch (const std::length_error&) { + } + } +#endif + + { + std::basic_string, tiny_size_allocator<32, CharT>> str; + str.resize(str.max_size()); + assert(str.size() == str.max_size()); + } } TEST_CONSTEXPR_CXX20 bool test() { @@ -66,6 +73,11 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string, safe_allocator>>(); #endif + test_max_size(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_max_size(); +#endif + return true; } diff --git a/libcxx/test/support/min_allocator.h b/libcxx/test/support/min_allocator.h index 18f51f8072640d1..afb6343054e5400 100644 --- a/libcxx/test/support/min_allocator.h +++ b/libcxx/test/support/min_allocator.h @@ -480,4 +480,32 @@ class safe_allocator { TEST_CONSTEXPR_CXX20 friend bool operator!=(safe_allocator x, safe_allocator y) { return !(x == y); } }; +template +struct tiny_size_allocator { + using value_type = T; + using size_type = unsigned; + + template + struct rebind { + using other = tiny_size_allocator; + }; + + tiny_size_allocator() = default; + + template + TEST_CONSTEXPR_CXX20 tiny_size_allocator(tiny_size_allocator) {} + + TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { + assert(n <= MaxSize); + return std::allocator().allocate(n); + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* ptr, std::size_t n) { std::allocator().deallocate(ptr, n); } + + TEST_CONSTEXPR_CXX20 size_type max_size() const { return MaxSize; } + + friend bool operator==(tiny_size_allocator, tiny_size_allocator) { return true; } + friend bool operator!=(tiny_size_allocator, tiny_size_allocator) { return false; } +}; + #endif // MIN_ALLOCATOR_H From libcxx-commits at lists.llvm.org Mon Feb 3 07:42:18 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 07:42:18 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libcxxabi] [libunwind] [llvm] [libc++] Enable -Wmissing-prototypes (PR #116261) In-Reply-To: Message-ID: <67a0e3da.170a0220.306b33.d6a9@mx.google.com> https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/116261 >From 0e74a8e32645d9b813e095e7cc17f092408ef12d Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Thu, 14 Nov 2024 18:30:39 +0100 Subject: [PATCH] [libc++] Enable -Wmissing-prototypes --- libcxx/include/fstream | 2 +- libcxx/src/charconv.cpp | 5 ++++- libcxx/src/experimental/time_zone.cpp | 2 +- libcxx/src/experimental/tzdb.cpp | 3 +++ libcxx/src/filesystem/int128_builtins.cpp | 2 ++ libcxx/src/include/from_chars_floating_point.h | 4 ++-- libcxx/src/support/win32/compiler_rt_shims.cpp | 2 ++ libcxx/src/support/win32/locale_win32.cpp | 2 +- libcxxabi/src/cxa_personality.cpp | 5 +++++ libcxxabi/src/private_typeinfo.cpp | 6 ++++++ libunwind/include/unwind_arm_ehabi.h | 2 +- libunwind/include/unwind_itanium.h | 3 +++ libunwind/src/UnwindLevel1.c | 1 - libunwind/src/Unwind_AIXExtras.cpp | 1 + libunwind/src/libunwind_ext.h | 1 + runtimes/cmake/Modules/WarningFlags.cmake | 1 + 16 files changed, 34 insertions(+), 8 deletions(-) diff --git a/libcxx/include/fstream b/libcxx/include/fstream index de5c07035dba9c3..d25e33f01e5f76e 100644 --- a/libcxx/include/fstream +++ b/libcxx/include/fstream @@ -220,7 +220,7 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_WIN32API) +# if _LIBCPP_STD_VER >= 23 && defined(_LIBCPP_WIN32API) _LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) noexcept; # endif diff --git a/libcxx/src/charconv.cpp b/libcxx/src/charconv.cpp index 5e8cb7d97703b43..4621df05066997e 100644 --- a/libcxx/src/charconv.cpp +++ b/libcxx/src/charconv.cpp @@ -18,9 +18,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace __itoa { +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes") +// These functions exist for ABI compatibility, so we don't ever want a declaration. _LIBCPP_EXPORTED_FROM_ABI char* __u32toa(uint32_t value, char* buffer) noexcept { return __base_10_u32(buffer, value); } - _LIBCPP_EXPORTED_FROM_ABI char* __u64toa(uint64_t value, char* buffer) noexcept { return __base_10_u64(buffer, value); } +_LIBCPP_DIAGNOSTIC_POP } // namespace __itoa diff --git a/libcxx/src/experimental/time_zone.cpp b/libcxx/src/experimental/time_zone.cpp index f7d82a5d4cfc30c..44ca807fe5c1d5d 100644 --- a/libcxx/src/experimental/time_zone.cpp +++ b/libcxx/src/experimental/time_zone.cpp @@ -711,7 +711,7 @@ __get_sys_info(sys_seconds __time, // Iff the "offsets" are the same '__current.__end' is replaced with // '__next.__end', which effectively merges the two objects in one object. The // function returns true if a merge occurred. -[[nodiscard]] bool __merge_continuation(sys_info& __current, const sys_info& __next) { +[[nodiscard]] static bool __merge_continuation(sys_info& __current, const sys_info& __next) { if (__current.end != __next.begin) return false; diff --git a/libcxx/src/experimental/tzdb.cpp b/libcxx/src/experimental/tzdb.cpp index f38f495c2d0bbe2..a3861894a045d6b 100644 --- a/libcxx/src/experimental/tzdb.cpp +++ b/libcxx/src/experimental/tzdb.cpp @@ -49,6 +49,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace chrono { +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes") // This function is weak so it can be overriden in the tests. The // declaration is in the test header test/support/test_tzdb.h _LIBCPP_WEAK string_view __libcpp_tzdb_directory() { @@ -58,6 +60,7 @@ _LIBCPP_WEAK string_view __libcpp_tzdb_directory() { # error "unknown path to the IANA Time Zone Database" #endif } +_LIBCPP_DIAGNOSTIC_POP //===----------------------------------------------------------------------===// // Details diff --git a/libcxx/src/filesystem/int128_builtins.cpp b/libcxx/src/filesystem/int128_builtins.cpp index da6f39e7d78b602..e811b3e6f912dbc 100644 --- a/libcxx/src/filesystem/int128_builtins.cpp +++ b/libcxx/src/filesystem/int128_builtins.cpp @@ -16,6 +16,8 @@ #include <__config> #include +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes") // See the FIXME above + #if _LIBCPP_HAS_INT128 extern "C" __attribute__((no_sanitize("undefined"))) _LIBCPP_EXPORTED_FROM_ABI __int128_t diff --git a/libcxx/src/include/from_chars_floating_point.h b/libcxx/src/include/from_chars_floating_point.h index 19eeeb28fb08d24..81d2180cc948058 100644 --- a/libcxx/src/include/from_chars_floating_point.h +++ b/libcxx/src/include/from_chars_floating_point.h @@ -193,7 +193,7 @@ struct __exponent_result { // __offset, 0, false. This allows using the results unconditionally, the // __present is important for the scientific notation, where the value is // mandatory. -__exponent_result __parse_exponent(const char* __input, size_t __n, size_t __offset, char __marker) { +static __exponent_result __parse_exponent(const char* __input, size_t __n, size_t __offset, char __marker) { if (__offset + 1 < __n && // an exponent always needs at least one digit. std::tolower(__input[__offset]) == __marker && // !std::isspace(__input[__offset + 1]) // leading whitespace is not allowed. @@ -213,7 +213,7 @@ __exponent_result __parse_exponent(const char* __input, size_t __n, size_t __off } // Here we do this operation as int64 to avoid overflow. -int32_t __merge_exponents(int64_t __fractional, int64_t __exponent, int __max_biased_exponent) { +static int32_t __merge_exponents(int64_t __fractional, int64_t __exponent, int __max_biased_exponent) { int64_t __sum = __fractional + __exponent; if (__sum > __max_biased_exponent) diff --git a/libcxx/src/support/win32/compiler_rt_shims.cpp b/libcxx/src/support/win32/compiler_rt_shims.cpp index ab263224906ed13..0953f6ade8c19e7 100644 --- a/libcxx/src/support/win32/compiler_rt_shims.cpp +++ b/libcxx/src/support/win32/compiler_rt_shims.cpp @@ -14,6 +14,8 @@ #include #include +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes") // See comment above + template static std::__complex_t mul_impl(T a, T b, T c, T d) { T __ac = a * c; diff --git a/libcxx/src/support/win32/locale_win32.cpp b/libcxx/src/support/win32/locale_win32.cpp index 24402e818d95d52..26722e6e47a7391 100644 --- a/libcxx/src/support/win32/locale_win32.cpp +++ b/libcxx/src/support/win32/locale_win32.cpp @@ -144,7 +144,7 @@ int __snprintf(char* ret, size_t n, __locale_t loc, const char* format, ...) { // Like sprintf, but when return value >= 0 it returns // a pointer to a malloc'd string in *sptr. // If return >= 0, use free to delete *sptr. -int __libcpp_vasprintf(char** sptr, const char* __restrict format, va_list ap) { +static int __libcpp_vasprintf(char** sptr, const char* __restrict format, va_list ap) { *sptr = nullptr; // Query the count required. va_list ap_copy; diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp index 5f6e75c5be19ce4..1836fba5ab5dd50 100644 --- a/libcxxabi/src/cxa_personality.cpp +++ b/libcxxabi/src/cxa_personality.cpp @@ -22,6 +22,11 @@ #include "private_typeinfo.h" #include "unwind.h" +// The functions defined in this file are magic functions called only by the compiler. +#ifdef __clang__ +# pragma clang diagnostic ignored "-Wmissing-prototypes" +#endif + // TODO: This is a temporary workaround for libc++abi to recognize that it's being // built against LLVM's libunwind. LLVM's libunwind started reporting _LIBUNWIND_VERSION // in LLVM 15 -- we can remove this workaround after shipping LLVM 17. Once we remove diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp index 01a1d2603b18d0f..d185f2618a7eab4 100644 --- a/libcxxabi/src/private_typeinfo.cpp +++ b/libcxxabi/src/private_typeinfo.cpp @@ -831,6 +831,10 @@ bool __pointer_to_member_type_info::can_catch_nested( #pragma clang diagnostic ignored "-Wmissing-field-initializers" #endif +#pragma GCC diagnostic push +// __dynamic_cast is called by the compiler, so there is no prototype +#pragma GCC diagnostic ignored "-Wmissing-prototypes" + // __dynamic_cast // static_ptr: pointer to an object of type static_type; nonnull, and since the @@ -953,6 +957,8 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, return const_cast(dst_ptr); } +#pragma GCC diagnostic pop + #ifdef __clang__ #pragma clang diagnostic pop #endif diff --git a/libunwind/include/unwind_arm_ehabi.h b/libunwind/include/unwind_arm_ehabi.h index 6277a1457f89660..1b65517ec838fbc 100644 --- a/libunwind/include/unwind_arm_ehabi.h +++ b/libunwind/include/unwind_arm_ehabi.h @@ -126,7 +126,7 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, _Unwind_VRS_DataRepresentation representation); #if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE) -#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern +#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern __inline__ #else #define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__ #endif diff --git a/libunwind/include/unwind_itanium.h b/libunwind/include/unwind_itanium.h index d94a6183be2901e..5940a542f46d429 100644 --- a/libunwind/include/unwind_itanium.h +++ b/libunwind/include/unwind_itanium.h @@ -69,6 +69,9 @@ extern void _Unwind_SetGR(struct _Unwind_Context *context, int index, extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value); +extern _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception *, + struct _Unwind_Context *); + #ifdef __cplusplus } #endif diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c index 7e785f4d31e716a..e7e2b6ef624dcec 100644 --- a/libunwind/src/UnwindLevel1.c +++ b/libunwind/src/UnwindLevel1.c @@ -181,7 +181,6 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except } return _URC_NO_REASON; } -extern int __unw_step_stage2(unw_cursor_t *); #if defined(_LIBUNWIND_USE_GCS) // Enable the GCS target feature to permit gcspop instructions to be used. diff --git a/libunwind/src/Unwind_AIXExtras.cpp b/libunwind/src/Unwind_AIXExtras.cpp index 66194ab4a16ba22..97b6c3e5e01aea3 100644 --- a/libunwind/src/Unwind_AIXExtras.cpp +++ b/libunwind/src/Unwind_AIXExtras.cpp @@ -10,6 +10,7 @@ // This file is only used for AIX. #if defined(_AIX) +#include "AddressSpace.hpp" #include "config.h" #include "libunwind_ext.h" #include diff --git a/libunwind/src/libunwind_ext.h b/libunwind/src/libunwind_ext.h index 28db43a4f6eef20..306ed41b3db6311 100644 --- a/libunwind/src/libunwind_ext.h +++ b/libunwind/src/libunwind_ext.h @@ -26,6 +26,7 @@ extern "C" { extern int __unw_getcontext(unw_context_t *); extern int __unw_init_local(unw_cursor_t *, unw_context_t *); extern int __unw_step(unw_cursor_t *); +extern int __unw_step_stage2(unw_cursor_t *); extern int __unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *); extern int __unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *); extern int __unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t); diff --git a/runtimes/cmake/Modules/WarningFlags.cmake b/runtimes/cmake/Modules/WarningFlags.cmake index d17bf92389d0b00..15e6772c2fae98a 100644 --- a/runtimes/cmake/Modules/WarningFlags.cmake +++ b/runtimes/cmake/Modules/WarningFlags.cmake @@ -25,6 +25,7 @@ function(cxx_add_warning_flags target enable_werror enable_pedantic) -Wformat-nonliteral -Wzero-length-array -Wdeprecated-redundant-constexpr-static-def + -Wmissing-prototypes ) if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") From libcxx-commits at lists.llvm.org Mon Feb 3 07:46:30 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Mon, 03 Feb 2025 07:46:30 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Simplify vector::__construct_at_end (Reopend) (PR #119632) In-Reply-To: Message-ID: <67a0e4d6.170a0220.2f7996.1aec@mx.google.com> ================ @@ -552,36 +552,29 @@ vector::__recommend(size_type __new_size) const { } // Default constructs __n objects starting at __end_ -// Precondition: __n > 0 // Precondition: size() + __n <= capacity() // Postcondition: size() == size() + __n template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__construct_at_end(size_type __n, bool __x) { - size_type __old_size = this->__size_; + _LIBCPP_ASSERT_INTERNAL( + capacity() >= size() + __n, "vector::__construct_at_end called with insufficient capacity"); + std::fill_n(end(), __n, __x); this->__size_ += __n; - if (__old_size == 0 || ((__old_size - 1) / __bits_per_word) != ((this->__size_ - 1) / __bits_per_word)) { - if (this->__size_ <= __bits_per_word) - this->__begin_[0] = __storage_type(0); - else - this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0); - } - std::fill_n(__make_iter(__old_size), __n, __x); + if (end().__ctz_ != 0) // Ensure uninitialized leading bits in the last word are set to zero + std::fill_n(end(), __bits_per_word - end().__ctz_, 0); ---------------- winner245 wrote: In constant evaluation, we have no uninitialized bits at all because `__vallocate` guarantees that the allocated memory is default-constructed. In non-constant evaluation, we effectively only reads from bits within the bounds of `vector` since we utilize bit masks. So in this case, the purpose of the initialization is to make sanitizer tools happy. According to my test, sanitizers do not complain as long as the unused bits in the last word are initialized to 0 within `__construct_at_end`, regardless of whether this occurs before or after the initialization of other words. However, without the initialization of unused bits, subsequent read from `vector` would trigger a Msan CI failure. https://github.com/llvm/llvm-project/pull/119632 From libcxx-commits at lists.llvm.org Mon Feb 3 07:54:50 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Mon, 03 Feb 2025 07:54:50 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::move{, _backward} for vector::iterator (PR #121109) In-Reply-To: Message-ID: <67a0e6ca.620a0220.3aa1e6.ffa8@mx.google.com> https://github.com/winner245 edited https://github.com/llvm/llvm-project/pull/121109 From libcxx-commits at lists.llvm.org Mon Feb 3 07:55:03 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Mon, 03 Feb 2025 07:55:03 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::move{, _backward} for vector::iterator (PR #121109) In-Reply-To: Message-ID: <67a0e6d7.050a0220.19b239.7307@mx.google.com> https://github.com/winner245 edited https://github.com/llvm/llvm-project/pull/121109 From libcxx-commits at lists.llvm.org Mon Feb 3 07:55:13 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Mon, 03 Feb 2025 07:55:13 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::move{, _backward} for vector::iterator (PR #121109) In-Reply-To: Message-ID: <67a0e6e1.630a0220.a2ffa.e966@mx.google.com> https://github.com/winner245 ready_for_review https://github.com/llvm/llvm-project/pull/121109 From libcxx-commits at lists.llvm.org Mon Feb 3 07:57:05 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Mon, 03 Feb 2025 07:57:05 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::move{, _backward} for vector::iterator (PR #121109) In-Reply-To: Message-ID: <67a0e751.170a0220.8879a.da50@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-libcxx Author: Peng Liu (winner245)
Changes As a follow-up to #121013 (which optimized `ranges::copy`) and #121026 (which optimized `ranges::copy_backward`), this PR enhances the performance of `std::ranges::{move, move_backward}` for `vector<bool>::iterator`, addressing a subtask outlined in issue #64038. The optimizations bring performance improvements analogous to those achieved for the `{copy, copy_backward}` algorithms: up to **2000x** for aligned moves and **60x** for unaligned moves. Moreover, comprehensive tests covering up to 4 storage words (256 bytes) with odd and even bit sizes are provided, which validate the proposed optimizations in this patch. ### Benchmarks #### Aligned move (up to 2406x) ``` ----------------------------------------------------------------------------- Benchmark Before After Improvement ----------------------------------------------------------------------------- bm_ranges_move_vb_aligned/8 11.3 ns 4.80 ns 2.4x bm_ranges_move_vb_aligned/64 89.5 ns 5.33 ns 16.8x bm_ranges_move_vb_aligned/512 716 ns 5.05 ns 142x bm_ranges_move_vb_aligned/4096 5662 ns 9.84 ns 575x bm_ranges_move_vb_aligned/32768 44880 ns 46.1 ns 973x bm_ranges_move_vb_aligned/65536 90616 ns 79.3 ns 1143x bm_ranges_move_vb_aligned/102400 144683 ns 67.0 ns 2159x bm_ranges_move_vb_aligned/106496 150643 ns 68.5 ns 2199x bm_ranges_move_vb_aligned/110592 158098 ns 70.3 ns 2249x bm_ranges_move_vb_aligned/114688 168557 ns 74.9 ns 2250x bm_ranges_move_vb_aligned/118784 169404 ns 77.6 ns 2183x bm_ranges_move_vb_aligned/122880 173890 ns 80.0 ns 2174x bm_ranges_move_vb_aligned/126976 179472 ns 81.2 ns 2210x bm_ranges_move_vb_aligned/131072 182714 ns 86.5 ns 2112x bm_ranges_move_vb_aligned/135168 190121 ns 87.8 ns 2165x bm_ranges_move_vb_aligned/139264 197667 ns 90.1 ns 2193x bm_ranges_move_vb_aligned/143360 211083 ns 87.7 ns 2406x bm_ranges_move_vb_aligned/147456 225014 ns 89.6 ns 2511x bm_ranges_move_vb_aligned/151552 219499 ns 91.4 ns 2402x bm_ranges_move_vb_aligned/155648 224825 ns 99.0 ns 2271x bm_ranges_move_vb_aligned/159744 227261 ns 103 ns 2206x bm_ranges_move_vb_aligned/163840 229928 ns 182 ns 1263x bm_ranges_move_vb_aligned/167936 226347 ns 212 ns 1068x bm_ranges_move_vb_aligned/172032 238817 ns 142 ns 1682x bm_ranges_move_vb_aligned/176128 257062 ns 121 ns 2124x bm_ranges_move_vb_aligned/180224 262250 ns 122 ns 2150x bm_ranges_move_vb_aligned/184320 261486 ns 118 ns 2216x bm_ranges_move_vb_aligned/188416 269745 ns 127 ns 2124x bm_ranges_move_vb_aligned/192512 271024 ns 128 ns 2117x bm_ranges_move_vb_aligned/196608 275733 ns 228 ns 1209x bm_ranges_move_vb_aligned/200704 278653 ns 285 ns 978x bm_ranges_move_vb_aligned/204800 286797 ns 243 ns 1180x ``` #### Aligned move_backward (up to 2226x) ``` ------------------------------------------------------------------------------------- Benchmark Before After Improvement ------------------------------------------------------------------------------------- bm_ranges_move_backward_vb_aligned/8 9.72 ns 5.03 ns 1.9x bm_ranges_move_backward_vb_aligned/64 89.8 ns 5.23 ns 17.2x bm_ranges_move_backward_vb_aligned/512 643 ns 5.18 ns 124x bm_ranges_move_backward_vb_aligned/4096 5037 ns 10.1 ns 499x bm_ranges_move_backward_vb_aligned/32768 40126 ns 44.9 ns 894x bm_ranges_move_backward_vb_aligned/65536 80262 ns 77.5 ns 1036x bm_ranges_move_backward_vb_aligned/102400 125445 ns 64.0 ns 1960x bm_ranges_move_backward_vb_aligned/106496 131869 ns 69.0 ns 1911x bm_ranges_move_backward_vb_aligned/110592 142678 ns 64.1 ns 2226x bm_ranges_move_backward_vb_aligned/114688 141358 ns 65.1 ns 2171x bm_ranges_move_backward_vb_aligned/118784 148357 ns 66.5 ns 2231x bm_ranges_move_backward_vb_aligned/122880 151052 ns 68.8 ns 2196x bm_ranges_move_backward_vb_aligned/126976 158514 ns 71.4 ns 2220x bm_ranges_move_backward_vb_aligned/131072 163450 ns 73.5 ns 2224x bm_ranges_move_backward_vb_aligned/135168 170184 ns 158 ns 1077x bm_ranges_move_backward_vb_aligned/139264 172592 ns 103 ns 1676x bm_ranges_move_backward_vb_aligned/143360 179955 ns 93.9 ns 1916x bm_ranges_move_backward_vb_aligned/147456 185436 ns 95.1 ns 1950x bm_ranges_move_backward_vb_aligned/151552 194811 ns 94.4 ns 2064x bm_ranges_move_backward_vb_aligned/155648 195126 ns 96.3 ns 2026x bm_ranges_move_backward_vb_aligned/159744 203279 ns 99.6 ns 2041x bm_ranges_move_backward_vb_aligned/163840 208438 ns 174 ns 1198x bm_ranges_move_backward_vb_aligned/167936 211036 ns 209 ns 1010x bm_ranges_move_backward_vb_aligned/172032 217071 ns 139 ns 1562x bm_ranges_move_backward_vb_aligned/176128 226155 ns 117 ns 1933x bm_ranges_move_backward_vb_aligned/180224 232424 ns 117 ns 1987x bm_ranges_move_backward_vb_aligned/184320 236457 ns 117 ns 2021x bm_ranges_move_backward_vb_aligned/188416 240821 ns 127 ns 1896x bm_ranges_move_backward_vb_aligned/192512 247794 ns 127 ns 1951x bm_ranges_move_backward_vb_aligned/196608 243881 ns 217 ns 1124x bm_ranges_move_backward_vb_aligned/200704 255730 ns 286 ns 894x bm_ranges_move_backward_vb_aligned/204800 245215 ns 237 ns 1035x ``` #### Unaligned move_backward (up to 62x) ``` ----------------------------------------------------------------------------- Benchmark Before After Improvement ----------------------------------------------------------------------------- bm_ranges_move_vb_unaligned/8 11.4 ns 8.64 ns 1.3x bm_ranges_move_vb_unaligned/64 96.5 ns 8.18 ns 12x bm_ranges_move_vb_unaligned/512 755 ns 17.9 ns 42x bm_ranges_move_vb_unaligned/4096 6013 ns 97.7 ns 62x bm_ranges_move_vb_unaligned/32768 47906 ns 781 ns 61x bm_ranges_move_vb_unaligned/262144 384167 ns 6201 ns 62x bm_ranges_move_vb_unaligned/1048576 1521607 ns 25520 ns 60x ``` #### Unaligned move_backward (up to 64x) ``` ------------------------------------------------------------------------------------- Benchmark Before After Improvement ------------------------------------------------------------------------------------- bm_ranges_move_backward_vb_unaligned/8 10.00 ns 9.61 ns 1.0x bm_ranges_move_backward_vb_unaligned/64 88.4 ns 8.53 ns 10x bm_ranges_move_backward_vb_unaligned/512 656 ns 17.8 ns 37x bm_ranges_move_backward_vb_unaligned/4096 5238 ns 102 ns 51x bm_ranges_move_backward_vb_unaligned/32768 42843 ns 706 ns 61x bm_ranges_move_backward_vb_unaligned/262144 339261 ns 5803 ns 58x bm_ranges_move_backward_vb_unaligned/1048576 1484360 ns 23332 ns 64x ``` --- Patch is 35.53 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/121109.diff 10 Files Affected: - (modified) libcxx/docs/ReleaseNotes/21.rst (+2-3) - (modified) libcxx/include/__algorithm/move.h (+10) - (modified) libcxx/include/__algorithm/move_backward.h (+10) - (modified) libcxx/include/__bit_reference (-16) - (added) libcxx/test/benchmarks/algorithms/move.bench.cpp (+55) - (added) libcxx/test/benchmarks/algorithms/move_backward.bench.cpp (+55) - (modified) libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp (+42-11) - (modified) libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp (+44-16) - (modified) libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp (+74-33) - (modified) libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp (+84-34) ``````````diff diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad3942..9b3e120e4bfd64 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -43,9 +43,8 @@ Implemented Papers Improvements and New Features ----------------------------- -- The ``std::ranges::{copy, copy_n, copy_backward}`` algorithms have been optimized for ``std::vector::iterator``\s, - resulting in a performance improvement of up to 2000x. - +- The ``std::ranges::{copy, copy_n, copy_backward, move, move_backward}`` algorithms have been optimized for + ``std::vector::iterator``, resulting in a performance improvement of up to 2000x. Deprecations and Removals ------------------------- diff --git a/libcxx/include/__algorithm/move.h b/libcxx/include/__algorithm/move.h index 6f3b0eb5d2927c..a3320e9f1985d0 100644 --- a/libcxx/include/__algorithm/move.h +++ b/libcxx/include/__algorithm/move.h @@ -9,11 +9,13 @@ #ifndef _LIBCPP___ALGORITHM_MOVE_H #define _LIBCPP___ALGORITHM_MOVE_H +#include <__algorithm/copy.h> #include <__algorithm/copy_move_common.h> #include <__algorithm/for_each_segment.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/min.h> #include <__config> +#include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> #include <__type_traits/common_type.h> @@ -98,6 +100,14 @@ struct __move_impl { } } + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> > + operator()(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + return std::__copy(__first, __last, __result); + } + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> diff --git a/libcxx/include/__algorithm/move_backward.h b/libcxx/include/__algorithm/move_backward.h index 24a8d9b24527a7..14482fee181147 100644 --- a/libcxx/include/__algorithm/move_backward.h +++ b/libcxx/include/__algorithm/move_backward.h @@ -9,10 +9,12 @@ #ifndef _LIBCPP___ALGORITHM_MOVE_BACKWARD_H #define _LIBCPP___ALGORITHM_MOVE_BACKWARD_H +#include <__algorithm/copy_backward.h> #include <__algorithm/copy_move_common.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/min.h> #include <__config> +#include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> #include <__type_traits/common_type.h> @@ -107,6 +109,14 @@ struct __move_backward_impl { } } + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> > + operator()(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + return std::__copy_backward<_ClassicAlgPolicy>(__first, __last, __result); + } + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c39805..c4e00769715479 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -186,22 +186,6 @@ private: __mask_(__m) {} }; -// move - -template -inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> -move(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - return std::copy(__first, __last, __result); -} - -// move_backward - -template -inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> move_backward( - __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - return std::copy_backward(__first, __last, __result); -} - // swap_ranges template diff --git a/libcxx/test/benchmarks/algorithms/move.bench.cpp b/libcxx/test/benchmarks/algorithms/move.bench.cpp new file mode 100644 index 00000000000000..909c0c4f1b4c58 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/move.bench.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +static void bm_ranges_move_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto dst = aligned ? out.begin() : out.begin() + 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::move(in, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_move_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto beg = in.begin(); + auto end = in.end(); + auto dst = aligned ? out.begin() : out.begin() + 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::move(beg, end, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_ranges_move_vb_aligned(benchmark::State& state) { bm_ranges_move_vb(state, true); } +static void bm_ranges_move_vb_unaligned(benchmark::State& state) { bm_ranges_move_vb(state, false); } + +static void bm_move_vb_aligned(benchmark::State& state) { bm_move_vb(state, true); } +static void bm_move_vb_unaligned(benchmark::State& state) { bm_move_vb(state, false); } + +// Test std::ranges::move for vector::iterator +BENCHMARK(bm_ranges_move_vb_aligned)->Range(8, 1 << 16)->DenseRange(102400, 204800, 4096); +BENCHMARK(bm_ranges_move_vb_unaligned)->Range(8, 1 << 20); + +// Test std::move for vector::iterator +BENCHMARK(bm_move_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_move_vb_unaligned)->Range(8, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp new file mode 100644 index 00000000000000..48b1a776bf4dd9 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +static void bm_ranges_move_backward_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto dst = aligned ? out.end() : out.end() - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::move_backward(in, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_move_backward(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto beg = in.begin(); + auto end = in.end(); + auto dst = aligned ? out.end() : out.end() - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::move_backward(beg, end, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_ranges_move_backward_vb_aligned(benchmark::State& state) { bm_ranges_move_backward_vb(state, true); } +static void bm_ranges_move_backward_vb_unaligned(benchmark::State& state) { bm_ranges_move_backward_vb(state, false); } + +static void bm_move_backward_vb_aligned(benchmark::State& state) { bm_move_backward(state, true); } +static void bm_move_backward_vb_unaligned(benchmark::State& state) { bm_move_backward(state, false); } + +// Test std::ranges::move_backward for vector::iterator +BENCHMARK(bm_ranges_move_backward_vb_aligned)->Range(8, 1 << 16)->DenseRange(102400, 204800, 4096); +BENCHMARK(bm_ranges_move_backward_vb_unaligned)->Range(8, 1 << 20); + +// Test std::move_backward for vector::iterator +BENCHMARK(bm_move_backward_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_move_backward_vb_unaligned)->Range(8, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp index b1ad6873bc5e5a..8b414b061105f2 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "MoveOnly.h" #include "test_iterators.h" @@ -45,15 +46,15 @@ struct Test { template TEST_CONSTEXPR_CXX20 void operator()() { const unsigned N = 1000; - int ia[N] = {}; + int ia[N] = {}; for (unsigned i = 0; i < N; ++i) - ia[i] = i; + ia[i] = i; int ib[N] = {0}; - OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib)); - assert(base(r) == ib+N); + OutIter r = std::move(InIter(ia), InIter(ia + N), OutIter(ib)); + assert(base(r) == ib + N); for (unsigned i = 0; i < N; ++i) - assert(ia[i] == ib[i]); + assert(ia[i] == ib[i]); } }; @@ -73,13 +74,13 @@ struct Test1 { const unsigned N = 100; std::unique_ptr ia[N]; for (unsigned i = 0; i < N; ++i) - ia[i].reset(new int(i)); + ia[i].reset(new int(i)); std::unique_ptr ib[N]; - OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib)); - assert(base(r) == ib+N); + OutIter r = std::move(InIter(ia), InIter(ia + N), OutIter(ib)); + assert(base(r) == ib + N); for (unsigned i = 0; i < N; ++i) - assert(*ib[i] == static_cast(i)); + assert(*ib[i] == static_cast(i)); } }; @@ -92,6 +93,26 @@ struct Test1OutIters { } }; +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move with aligned bytes + std::vector out(N); + std::move(in.begin(), in.end(), out.begin()); + assert(in == out); + } + { // Test move with unaligned bytes + std::vector out(N + 8); + std::move(in.begin(), in.end(), out.begin() + 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::cpp17_input_iterator_list(), TestOutIters()); if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED) @@ -118,7 +139,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When non-trivial { MoveOnly from[3] = {1, 2, 3}; - MoveOnly to[3] = {}; + MoveOnly to[3] = {}; std::move(std::begin(from), std::end(from), std::begin(to)); assert(to[0] == MoveOnly(1)); assert(to[1] == MoveOnly(2)); @@ -127,7 +148,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When trivial { TrivialMoveOnly from[3] = {1, 2, 3}; - TrivialMoveOnly to[3] = {}; + TrivialMoveOnly to[3] = {}; std::move(std::begin(from), std::end(from), std::begin(to)); assert(to[0] == TrivialMoveOnly(1)); assert(to[1] == TrivialMoveOnly(2)); @@ -135,6 +156,16 @@ TEST_CONSTEXPR_CXX20 bool test() { } } + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } + return true; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp index 61dea47b510716..dfee9de2fa7687 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "MoveOnly.h" #include "test_iterators.h" @@ -44,24 +45,22 @@ struct Test { template TEST_CONSTEXPR_CXX20 void operator()() { const unsigned N = 1000; - int ia[N] = {}; + int ia[N] = {}; for (unsigned i = 0; i < N; ++i) - ia[i] = i; + ia[i] = i; int ib[N] = {0}; - OutIter r = std::move_backward(InIter(ia), InIter(ia+N), OutIter(ib+N)); + OutIter r = std::move_backward(InIter(ia), InIter(ia + N), OutIter(ib + N)); assert(base(r) == ib); for (unsigned i = 0; i < N; ++i) - assert(ia[i] == ib[i]); + assert(ia[i] == ib[i]); } }; struct TestOutIters { template TEST_CONSTEXPR_CXX20 void operator()() { - types::for_each( - types::concatenate_t >(), - Test()); + types::for_each(types::concatenate_t >(), Test()); } }; @@ -72,24 +71,44 @@ struct Test1 { const unsigned N = 100; std::unique_ptr ia[N]; for (unsigned i = 0; i < N; ++i) - ia[i].reset(new int(i)); + ia[i].reset(new int(i)); std::unique_ptr ib[N]; - OutIter r = std::move_backward(InIter(ia), InIter(ia+N), OutIter(ib+N)); + OutIter r = std::move_backward(InIter(ia), InIter(ia + N), OutIter(ib + N)); assert(base(r) == ib); for (unsigned i = 0; i < N; ++i) - assert(*ib[i] == static_cast(i)); + assert(*ib[i] == static_cast(i)); } }; struct Test1OutIters { template TEST_CONSTEXPR_CXX23 void operator()() { - types::for_each(types::concatenate_t*> >(), - Test1()); + types::for_each( + types::concatenate_t*> >(), Test1()); } }; +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test move_backward with aligned bytes + std::vector out(N); + std::move_backward(in.begin(), in.end(), out.end()); + assert(in == out); + } + { // Test move_backward with unaligned bytes + std::vector out(N + 8); + std::move_backward(in.begin(), in.end(), out.end() - 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::bidirectional_iterator_list(), TestOutIters()); if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED) @@ -117,7 +136,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When non-trivial { MoveOnly from[3] = {1, 2, 3}; - MoveOnly to[3] = {}; + MoveOnly to[3] = {}; std::move_backward(std::begin(from), std::end(from), std::end(to)); assert(to[0] == MoveOnly(1)); assert(to[1] == MoveOnly(2)); @@ -126,7 +145,7 @@ TEST_CONSTEXPR_CXX20 bool test() { // When trivial { TrivialMoveOnly from[3] = {1, 2, 3}; - TrivialMoveOnly to[3] = {}; + TrivialMoveOnly to[3] = {}; std::move_backward(std::begin(from), std::end(from), std::end(to)); assert(to[0] == TrivialMoveOnly(1)); assert(to[1] == TrivialMoveOnly(2)); @@ -134,11 +153,20 @@ TEST_CONSTEXPR_CXX20 bool test() { } } + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } + return true; } -int main(int, char**) -{ +int main(int, char**) { test(); #if TEST_STD_VER >= 20 static_assert(test()); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp index a0d1473360a14e..664631aea826b1 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp @@ -31,6 +31,7 @@ #include "almost_satisfies_types.h" #include "MoveOnly.h" #include "test_iterators.h" +#include "test_macros.h" template > concept HasMoveIt = requires(In in, Sent sent, Out out) { std::ranges::move(in, sent, out); }; @@ -65,7 +66,7 @@ constexpr void test(std::array in) { { std::array out; std::same_as> decltype(auto) ret = - std::ranges::move(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); + std::ranges::move(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data() + out.size()); @@ -73,8 +74,7 @@ constexpr void test(std::array in) { { std::array out; auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); - std::same_as> decltype(auto) ret = - std::ranges::move(range, Out(out.data())); + std::same_as> decltype(auto) ret = std::ranges::move(range, Out(out.data())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data() + out.size()); @@ -84,16 +84,16 @@ constexpr void test(std::array in) { template constexpr void test_containers() { { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); std::same_as> auto ret = - std::ranges::move(In(in.begin()), Sent(In(in.end())), Out(out.begin())); + std::ranges::move(In(in.begin()), Sent(In(in.end())), Out(out.begin())); assert(std::ranges::equal(in, out)); assert(base(ret.in) == in.end()); assert(base(ret.out) == out.end()); } { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); auto range = std::ranges::subrange(In(in.begin()), Sent(In(in.end()))); std::same_as> auto ret = std::ranges::move(range, Out(out.begin())); @@ -165,22 +165,51 @@ constexpr void test_proxy_in_iterators() { } struct IteratorWithMoveIter { - using value_type = int; - using difference_type = int; + using value_type = int; + using difference_type = int; explicit IteratorWithMoveIter() = default; int* ptr; constexpr IteratorWithMoveIter(int* ptr_) : ptr(ptr_) {} constexpr int& operator*() const; // iterator with iter_move should not be dereferenced - constexpr Iterato... [truncated] ``````````
https://github.com/llvm/llvm-project/pull/121109 From libcxx-commits at lists.llvm.org Mon Feb 3 08:35:21 2025 From: libcxx-commits at lists.llvm.org (David Tenty via libcxx-commits) Date: Mon, 03 Feb 2025 08:35:21 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Include the rest of the detail headers by version in the umbrella headers (PR #96032) In-Reply-To: Message-ID: <67a0f049.170a0220.26f962.f259@mx.google.com> daltenty wrote: @philnik777 this PR has some strange side-effects, namely it put `` (which is a C++20 header) in the transitive include set for language modes less that `C++20`. A few of our users report this has strange effects when using `C++17` with user headers named `format`. Is this change required? https://github.com/llvm/llvm-project/pull/96032 From libcxx-commits at lists.llvm.org Mon Feb 3 08:56:03 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 08:56:03 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Include the rest of the detail headers by version in the umbrella headers (PR #96032) In-Reply-To: Message-ID: <67a0f523.050a0220.2389d.1c67@mx.google.com> ldionne wrote: I don't fully understand -- aren't we including strictly less after this patch? https://github.com/llvm/llvm-project/pull/96032 From libcxx-commits at lists.llvm.org Mon Feb 3 08:58:37 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 08:58:37 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Reduce std::conjunction overhead (PR #124259) In-Reply-To: Message-ID: <67a0f5bd.170a0220.15e14c.e496@mx.google.com> ldionne wrote: Indeed, please provide a reproducer. We're fine with reverting temporarily when we have a reproducer and a bug report that is being worked on, but without that we're essentially reverting because someone said so, which is not really workable for the project. https://github.com/llvm/llvm-project/pull/124259 From libcxx-commits at lists.llvm.org Mon Feb 3 09:10:34 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Mon, 03 Feb 2025 09:10:34 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Reduce std::conjunction overhead (PR #124259) In-Reply-To: Message-ID: <67a0f88a.050a0220.3c4040.0e37@mx.google.com> asmok-g wrote: Indeed. cvise is running so we'll see where it is tomorrow https://github.com/llvm/llvm-project/pull/124259 From libcxx-commits at lists.llvm.org Mon Feb 3 09:10:50 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Mon, 03 Feb 2025 09:10:50 -0800 (PST) Subject: [libcxx-commits] [libcxx] c7c7eab - [libc++] Add a benchmark for std::reverse (#125262) Message-ID: <67a0f89a.170a0220.2a3003.36d6@mx.google.com> Author: Louis Dionne Date: 2025-02-03T12:10:47-05:00 New Revision: c7c7eabc7fc42433ed6a0a93ea14f279ad8d37af URL: https://github.com/llvm/llvm-project/commit/c7c7eabc7fc42433ed6a0a93ea14f279ad8d37af DIFF: https://github.com/llvm/llvm-project/commit/c7c7eabc7fc42433ed6a0a93ea14f279ad8d37af.diff LOG: [libc++] Add a benchmark for std::reverse (#125262) Added: libcxx/test/benchmarks/algorithms/reverse.bench.cpp Modified: Removed: ################################################################################ diff --git a/libcxx/test/benchmarks/algorithms/reverse.bench.cpp b/libcxx/test/benchmarks/algorithms/reverse.bench.cpp new file mode 100644 index 00000000000000..2d8dd819ac24c2 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/reverse.bench.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include +#include + +#include +#include "../GenerateInput.h" + +template +static void bm_reverse(benchmark::State& state) { + std::size_t const n = state.range(); + std::vector vec; + std::generate_n(std::back_inserter(vec), n, [] { return Generate::cheap(); }); + for (auto _ : state) { + std::reverse(vec.begin(), vec.end()); + benchmark::DoNotOptimize(vec); + } +} +BENCHMARK(bm_reverse)->Name("std::reverse(vector)")->DenseRange(1, 8)->Range(16, 1 << 20); +BENCHMARK(bm_reverse)->Name("std::reverse(vector)")->DenseRange(1, 8)->Range(16, 1 << 20); + +template +static void bm_ranges_reverse(benchmark::State& state) { + std::size_t const n = state.range(); + std::vector vec; + std::generate_n(std::back_inserter(vec), n, [] { return Generate::cheap(); }); + for (auto _ : state) { + std::ranges::reverse(vec.begin(), vec.end()); + benchmark::DoNotOptimize(vec); + } +} +BENCHMARK(bm_ranges_reverse)->Name("ranges::reverse(vector)")->DenseRange(1, 8)->Range(16, 1 << 20); +BENCHMARK(bm_ranges_reverse) + ->Name("ranges::reverse(vector)") + ->DenseRange(1, 8) + ->Range(16, 1 << 20); + +BENCHMARK_MAIN(); From libcxx-commits at lists.llvm.org Mon Feb 3 09:10:54 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 09:10:54 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add a benchmark for std::reverse (PR #125262) In-Reply-To: Message-ID: <67a0f89e.050a0220.1d15d.1897@mx.google.com> https://github.com/ldionne closed https://github.com/llvm/llvm-project/pull/125262 From libcxx-commits at lists.llvm.org Mon Feb 3 10:09:00 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:09:00 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) Message-ID: https://github.com/mordante created https://github.com/llvm/llvm-project/pull/125550 Implements parts of: - P0355 Extending to Calendars and Time Zones - P1361 Integration of chrono with text formatting - LWG3359 leap second support should allow for negative leap seconds >From 198180b2791c4e64886ff9bd81fb2d31ef45f23a Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sat, 25 Jan 2025 20:27:14 +0100 Subject: [PATCH] [libc++][chrono] implements TAI clock. Implements parts of: - P0355 Extending to Calendars and Time Zones - P1361 Integration of chrono with text formatting - LWG3359 leap second support should allow for negative leap seconds --- libcxx/docs/Status/FormatPaper.csv | 2 +- libcxx/include/CMakeLists.txt | 1 + libcxx/include/__chrono/convert_to_tm.h | 13 + libcxx/include/__chrono/formatter.h | 14 + libcxx/include/__chrono/ostream.h | 7 + libcxx/include/__chrono/tai_clock.h | 98 ++ libcxx/include/chrono | 31 + libcxx/include/module.modulemap | 4 + libcxx/modules/std/chrono.inc | 2 +- .../diagnostics/chrono.nodiscard.verify.cpp | 11 + .../time.clock.tai/tai_time.ostream.pass.cpp | 164 +++ .../time.clock.tai.members/from_utc.pass.cpp | 159 +++ .../time.clock.tai.members/now.pass.cpp | 30 + .../time.clock.tai.members/to_utc.pass.cpp | 161 +++ .../time.clock.tai/types.compile.pass.cpp | 59 ++ .../time/time.syn/formatter.tai_time.pass.cpp | 998 ++++++++++++++++++ libcxx/test/support/concat_macros.h | 5 + 17 files changed, 1757 insertions(+), 2 deletions(-) create mode 100644 libcxx/include/__chrono/tai_clock.h create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp create mode 100644 libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp diff --git a/libcxx/docs/Status/FormatPaper.csv b/libcxx/docs/Status/FormatPaper.csv index 343fa62f1356540..de64e9c25a7771b 100644 --- a/libcxx/docs/Status/FormatPaper.csv +++ b/libcxx/docs/Status/FormatPaper.csv @@ -3,7 +3,7 @@ Section,Description,Dependencies,Assignee,Status,First released version `[time.syn] `_,"Formatter ``chrono::duration``",,Mark de Wever,|Complete|,16 `[time.syn] `_,"Formatter ``chrono::sys_time``",,Mark de Wever,|Complete|,17 `[time.syn] `_,"Formatter ``chrono::utc_time``",A ```` implementation,Mark de Wever,|Complete|,20 -`[time.syn] `_,"Formatter ``chrono::tai_time``",A ```` implementation,Mark de Wever,,, ++`[time.syn] `_,"Formatter ``chrono::tai_time``",,Mark de Wever,|Complete|,21 `[time.syn] `_,"Formatter ``chrono::gps_time``",A ```` implementation,Mark de Wever,,, `[time.syn] `_,"Formatter ``chrono::file_time``",,Mark de Wever,|Complete|,17 `[time.syn] `_,"Formatter ``chrono::local_time``",,Mark de Wever,|Complete|,17 diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8dac823503d73f5..ce805b4eb7b8b4f 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -270,6 +270,7 @@ set(files __chrono/steady_clock.h __chrono/sys_info.h __chrono/system_clock.h + __chrono/tai_clock.h __chrono/time_point.h __chrono/time_zone.h __chrono/time_zone_link.h diff --git a/libcxx/include/__chrono/convert_to_tm.h b/libcxx/include/__chrono/convert_to_tm.h index 7d06a38d87f26df..934293ce382345d 100644 --- a/libcxx/include/__chrono/convert_to_tm.h +++ b/libcxx/include/__chrono/convert_to_tm.h @@ -23,6 +23,7 @@ #include <__chrono/statically_widen.h> #include <__chrono/sys_info.h> #include <__chrono/system_clock.h> +#include <__chrono/tai_clock.h> #include <__chrono/time_point.h> #include <__chrono/utc_clock.h> #include <__chrono/weekday.h> @@ -112,6 +113,16 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::utc_time<_Duration> __tp) { return __result; } +template +_LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::tai_time<_Duration> __tp) { + using _Rp = common_type_t<_Duration, chrono::seconds>; + // The time between the TAI epoch (1958-01-01) and UNIX epoch (1970-01-01). + // This avoids leap second conversion when going from TAI to UTC. + // (It also avoids issues when the date is before the UTC epoch.) + constexpr chrono::seconds __offset{4383 * 24 * 60 * 60}; + return std::__convert_to_tm<_Tm>(chrono::sys_time<_Rp>{__tp.time_since_epoch() - __offset}); +} + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION @@ -131,6 +142,8 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) { # if _LIBCPP_HAS_EXPERIMENTAL_TZDB else if constexpr (same_as) return std::__convert_to_tm<_Tm>(__value); + else if constexpr (same_as) + return std::__convert_to_tm<_Tm>(__value); # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION else if constexpr (same_as) diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h index d17acd274e4cda6..753a824a3c50d79 100644 --- a/libcxx/include/__chrono/formatter.h +++ b/libcxx/include/__chrono/formatter.h @@ -31,6 +31,7 @@ # include <__chrono/statically_widen.h> # include <__chrono/sys_info.h> # include <__chrono/system_clock.h> +# include <__chrono/tai_clock.h> # include <__chrono/time_point.h> # include <__chrono/utc_clock.h> # include <__chrono/weekday.h> @@ -231,6 +232,8 @@ _LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const # if _LIBCPP_HAS_EXPERIMENTAL_TZDB if constexpr (same_as<_Tp, chrono::sys_info>) return {__value.abbrev, __value.offset}; + else if constexpr (__is_time_point<_Tp> && requires { requires same_as; }) + return {"TAI", chrono::seconds{0}}; # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) return __formatter::__convert_to_time_zone(__value.get_info()); @@ -734,6 +737,17 @@ struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : pub } }; +template +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : public __formatter_chrono<_CharT> { +public: + using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); + } +}; + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM diff --git a/libcxx/include/__chrono/ostream.h b/libcxx/include/__chrono/ostream.h index ed9ad8e346ba94e..b8cd6a4680662b0 100644 --- a/libcxx/include/__chrono/ostream.h +++ b/libcxx/include/__chrono/ostream.h @@ -26,6 +26,7 @@ # include <__chrono/statically_widen.h> # include <__chrono/sys_info.h> # include <__chrono/system_clock.h> +# include <__chrono/tai_clock.h> # include <__chrono/utc_clock.h> # include <__chrono/weekday.h> # include <__chrono/year.h> @@ -71,6 +72,12 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const utc_time<_Duration>& __tp return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); } +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const tai_time<_Duration>& __tp) { + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); +} + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM diff --git a/libcxx/include/__chrono/tai_clock.h b/libcxx/include/__chrono/tai_clock.h new file mode 100644 index 000000000000000..18ba329b7b8fb49 --- /dev/null +++ b/libcxx/include/__chrono/tai_clock.h @@ -0,0 +1,98 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_TAI_CLOCK_H +#define _LIBCPP___CHRONO_TAI_CLOCK_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if _LIBCPP_HAS_EXPERIMENTAL_TZDB + +# include <__chrono/duration.h> +# include <__chrono/time_point.h> +# include <__chrono/utc_clock.h> +# include <__config> +# include <__type_traits/common_type.h> + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION + +namespace chrono { + +class tai_clock; + +template +using tai_time = time_point; +using tai_seconds = tai_time; + +// [time.clock.tai.overview]/1 +// The clock tai_clock measures seconds since 1958-01-01 00:00:00 and is +// offset 10s ahead of UTC at this date. That is, 1958-01-01 00:00:00 TAI is +// equivalent to 1957-12-31 23:59:50 UTC. Leap seconds are not inserted into +// TAI. Therefore every time a leap second is inserted into UTC, UTC shifts +// another second with respect to TAI. For example by 2000-01-01 there had +// been 22 positive and 0 negative leap seconds inserted so 2000-01-01 +// 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI (22s plus the +// initial 10s offset). +// +// Note this does not specify what the UTC offset before 1958-01-01 00:00:00 +// TAI is. However the member functions are fully specified in the standard. +// https://koka-lang.github.io/koka/doc/std_time_utc.html contains more +// information and references. +class tai_clock { +public: + using rep = utc_clock::rep; + using period = utc_clock::period; + using duration = chrono::duration; + using time_point = chrono::time_point; + static constexpr bool is_steady = false; // The utc_clock is not steady. + + // The static difference between UTC and TAI time. + static constexpr chrono::seconds __offset{378691210}; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static time_point now() { return from_utc(utc_clock::now()); } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static utc_time> + to_utc(const tai_time<_Duration>& __time) noexcept { + using _Rp = common_type_t<_Duration, seconds>; + _Duration __time_since_epoch = __time.time_since_epoch(); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch >= utc_time<_Rp>::min().time_since_epoch() + __offset, + "the TAI to UTC conversion would underflow"); + + return utc_time<_Rp>{__time_since_epoch - __offset}; + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static tai_time> + from_utc(const utc_time<_Duration>& __time) noexcept { + using _Rp = common_type_t<_Duration, seconds>; + _Duration __time_since_epoch = __time.time_since_epoch(); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch <= utc_time<_Rp>::max().time_since_epoch() - __offset, + "the UTC to TAI conversion would overflow"); + + return tai_time<_Rp>{__time_since_epoch + __offset}; + } +}; + +} // namespace chrono + +# endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && + // _LIBCPP_HAS_LOCALIZATION + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB + +#endif // _LIBCPP___CHRONO_TAI_CLOCK_H diff --git a/libcxx/include/chrono b/libcxx/include/chrono index 10695eea649fb70..bd4c98600440c48 100644 --- a/libcxx/include/chrono +++ b/libcxx/include/chrono @@ -335,6 +335,34 @@ struct leap_second_info { // C++20 template // C++20 leap_second_info get_leap_second_info(const utc_time& ut); + +// [time.clock.tai], class tai_clock +class tai_clock { // C++20 +public: + using rep = a signed arithmetic type; + using period = ratio; + using duration = chrono::duration; + using time_point = chrono::time_point; + static constexpr bool is_steady = unspecified; + + static time_point now(); + + template + static utc_time> + to_utc(const tai_time& t); + template + static tai_time> + from_utc(const utc_time& t); +}; + +template +using tai_time = time_point; // C++20 +using tai_seconds = tai_time; // C++20 + +template // C++20 + basic_ostream& + operator<<(basic_ostream& os, const tai_time& t); + class file_clock // C++20 { public: @@ -898,6 +926,8 @@ namespace std { struct formatter, charT>; // C++20 template struct formatter, charT>; // C++20 + template + struct formatter, charT>; // C++20 template struct formatter, charT>; // C++20 template @@ -1014,6 +1044,7 @@ constexpr chrono::year operator ""y(unsigned lo # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION # include <__chrono/leap_second.h> +# include <__chrono/tai_clock.h> # include <__chrono/time_zone.h> # include <__chrono/time_zone_link.h> # include <__chrono/tzdb.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4bae02137b37b21..fd39c946b992a43 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -967,6 +967,10 @@ module std [system] { header "__chrono/system_clock.h" export std.chrono.time_point } + module tai_clock { + header "__chrono/tai_clock.h" + export std.chrono.time_point + } module time_point { header "__chrono/time_point.h" } module time_zone_link { header "__chrono/time_zone_link.h" } module time_zone { header "__chrono/time_zone.h" } diff --git a/libcxx/modules/std/chrono.inc b/libcxx/modules/std/chrono.inc index 98f14f716c20784..43e8da36e904489 100644 --- a/libcxx/modules/std/chrono.inc +++ b/libcxx/modules/std/chrono.inc @@ -97,13 +97,13 @@ export namespace std { using std::chrono::get_leap_second_info; -# if 0 // [time.clock.tai], class tai_clock using std::chrono::tai_clock; using std::chrono::tai_seconds; using std::chrono::tai_time; +# if 0 // [time.clock.gps], class gps_clock using std::chrono::gps_clock; diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp index 644c5b598c018d6..bb40e0cfc4e1b8a 100644 --- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp +++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp @@ -102,4 +102,15 @@ void test(std::chrono::time_zone tz, std::chrono::time_zone_link link, std::chro zt.get_sys_time(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} zt.get_info(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} } + + { // [time.clock.tai] + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::now(); + + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::to_utc(std::chrono::tai_seconds{}); + + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::from_utc(std::chrono::utc_seconds{}); + } } diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp new file mode 100644 index 000000000000000..3508ceb8b2d3f69 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp @@ -0,0 +1,164 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb +// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME + +// TODO FMT This test should not require std::to_chars(floating-point) +// XFAIL: availability-fp_to_chars-missing + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// REQUIRES: locale.fr_FR.UTF-8 +// REQUIRES: locale.ja_JP.UTF-8 + +// + +// class taitem_clock; + +// template +// basic_ostream& +// operator<<(basic_ostream& os, const tai_time& tp); + +#include +#include +#include +#include + +#include "make_string.h" +#include "platform_support.h" // locale name macros +#include "test_macros.h" + +#define SV(S) MAKE_STRING_VIEW(CharT, S) + +template +static std::basic_string stream_c_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static std::basic_string stream_fr_FR_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + const std::locale locale(LOCALE_fr_FR_UTF_8); + sstr.imbue(locale); + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static std::basic_string stream_ja_JP_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + const std::locale locale(LOCALE_ja_JP_UTF_8); + sstr.imbue(locale); + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static void test_c() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + assert(stream_c_locale(cr::tai_time{946'688'523'123'456'789ns}) == + SV("1988-01-01 01:02:03.123456789")); + assert(stream_c_locale(cr::tai_time{946'688'523'123'456us}) == + SV("1988-01-01 01:02:03.123456")); + + assert(stream_c_locale(cr::tai_time{946'684'822'123ms}) == SV("1988-01-01 00:00:22.123")); + assert(stream_c_locale(cr::tai_seconds{1'234'567'890s}) == SV("1997-02-13 23:31:30")); + assert(stream_c_locale(cr::tai_time{20'576'131min}) == SV("1997-02-13 23:31:00")); + assert(stream_c_locale(cr::tai_time{342'935h}) == SV("1997-02-13 23:00:00")); + + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{60}}) == SV("1958-01-01 00:02:00")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:30:00.0")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:15:00.00")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{36611}}) == SV("1958-01-01 01:01:01.1")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{12'345'678'9010}}) == SV("1997-02-13 23:31:30.10")); +} + +template +static void test_fr_FR() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + assert(stream_fr_FR_locale(cr::tai_time{946'688'523'123'456'789ns}) == + SV("1988-01-01 01:02:03,123456789")); + assert(stream_fr_FR_locale(cr::tai_time{946'688'523'123'456us}) == + SV("1988-01-01 01:02:03,123456")); + + assert(stream_fr_FR_locale(cr::tai_time{946'684'822'123ms}) == + SV("1988-01-01 00:00:22,123")); + assert(stream_fr_FR_locale(cr::tai_seconds{1'234'567'890s}) == SV("1997-02-13 23:31:30")); + assert(stream_fr_FR_locale(cr::tai_time{20'576'131min}) == SV("1997-02-13 23:31:00")); + assert(stream_fr_FR_locale(cr::tai_time{342'935h}) == SV("1997-02-13 23:00:00")); + + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{60}}) == SV("1958-01-01 00:02:00")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:30:00,0")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:15:00,00")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{36611}}) == SV("1958-01-01 01:01:01,1")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{12'345'678'9010}}) == SV("1997-02-13 23:31:30,10")); +} + +template +static void test_ja_JP() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + assert(stream_ja_JP_locale(cr::tai_time{946'688'523'123'456'789ns}) == + SV("1988-01-01 01:02:03.123456789")); + assert(stream_ja_JP_locale(cr::tai_time{946'688'523'123'456us}) == + SV("1988-01-01 01:02:03.123456")); + + assert(stream_ja_JP_locale(cr::tai_time{946'684'822'123ms}) == + SV("1988-01-01 00:00:22.123")); + assert(stream_ja_JP_locale(cr::tai_seconds{1'234'567'890s}) == SV("1997-02-13 23:31:30")); + assert(stream_ja_JP_locale(cr::tai_time{20'576'131min}) == SV("1997-02-13 23:31:00")); + assert(stream_ja_JP_locale(cr::tai_time{342'935h}) == SV("1997-02-13 23:00:00")); + + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{60}}) == SV("1958-01-01 00:02:00")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:30:00.0")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:15:00.00")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{36611}}) == SV("1958-01-01 01:01:01.1")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{12'345'678'9010}}) == SV("1997-02-13 23:31:30.10")); +} + +template +static void test() { + test_c(); + test_fr_FR(); + test_ja_JP(); +} + +int main(int, char**) { + test(); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + + return 0; +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp new file mode 100644 index 000000000000000..b3ba97bdc49dd9a --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp @@ -0,0 +1,159 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// +// +// class tai_clock; + +// static tai_time> +// from_utc(const utc<_Duration>& __time) noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "assert_macros.h" +#include "concat_macros.h" + +static void test_known_values() { + namespace cr = std::chrono; + using namespace std::literals::chrono_literals; + constexpr auto unix_to_tai_epoch_offset = cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + + // [time.clock.tai.overview]/1 + // ... 1958-01-01 00:00:00 TAI is equivalent to 1957-12-31 23:59:50 UTC + // ... 2000-01-01 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI + + assert(cr::tai_clock::from_utc(cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 1958} - 10s)) == + cr::tai_seconds{0s}); + + assert(cr::tai_clock::from_utc(cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 2000})) == + cr::tai_seconds{(cr::sys_days{cr::January / 1 / 2000} + unix_to_tai_epoch_offset).time_since_epoch()} + 32s); +} + +template +static void test_leap_seconds(std::chrono::utc_time utc, + std::chrono::tai_time expected, + std::source_location loc = std::source_location::current()) { + auto tai = std::chrono::tai_clock::from_utc(utc); + TEST_REQUIRE(tai == expected, + TEST_WRITE_CONCATENATED(loc, "\nExpected output ", expected, "\nActual output ", tai, '\n')); +} + +// Tests set if existing database entries at the time of writing. +static void test_transitions() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + // "sys" is the time of the transition to the next leap second. + // "elapsed" is the number of leap seconds before the transition. + auto test_transition = [](cr::sys_days sys, cr::seconds elapsed) { + constexpr auto unix_to_tai_epoch_offset = + cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + cr::tai_seconds tai{sys.time_since_epoch() + unix_to_tai_epoch_offset + elapsed}; + + test_leap_seconds(cr::utc_clock::from_sys(sys - 1ns), tai - 1ns); + test_leap_seconds(cr::utc_clock::from_sys(sys), tai + 1s); + test_leap_seconds(cr::utc_clock::from_sys(sys) + 1ns, tai + 1s + 1ns); + }; + + // Transitions from the start of UTC. + test_transition(cr::sys_days{cr::July / 1 / 1972}, 10s); + test_transition(cr::sys_days{cr::January / 1 / 1973}, 11s); + test_transition(cr::sys_days{cr::January / 1 / 1974}, 12s); + test_transition(cr::sys_days{cr::January / 1 / 1975}, 13s); + test_transition(cr::sys_days{cr::January / 1 / 1976}, 14s); + test_transition(cr::sys_days{cr::January / 1 / 1977}, 15s); + test_transition(cr::sys_days{cr::January / 1 / 1978}, 16s); + test_transition(cr::sys_days{cr::January / 1 / 1979}, 17s); + test_transition(cr::sys_days{cr::January / 1 / 1980}, 18s); + test_transition(cr::sys_days{cr::July / 1 / 1981}, 19s); + test_transition(cr::sys_days{cr::July / 1 / 1982}, 20s); + test_transition(cr::sys_days{cr::July / 1 / 1983}, 21s); + test_transition(cr::sys_days{cr::July / 1 / 1985}, 22s); + test_transition(cr::sys_days{cr::January / 1 / 1988}, 23s); + test_transition(cr::sys_days{cr::January / 1 / 1990}, 24s); + test_transition(cr::sys_days{cr::January / 1 / 1991}, 25s); + test_transition(cr::sys_days{cr::July / 1 / 1992}, 26s); + test_transition(cr::sys_days{cr::July / 1 / 1993}, 27s); + test_transition(cr::sys_days{cr::July / 1 / 1994}, 28s); + test_transition(cr::sys_days{cr::January / 1 / 1996}, 29s); + test_transition(cr::sys_days{cr::July / 1 / 1997}, 30s); + test_transition(cr::sys_days{cr::January / 1 / 1999}, 31s); + test_transition(cr::sys_days{cr::January / 1 / 2006}, 32s); + test_transition(cr::sys_days{cr::January / 1 / 2009}, 33s); + test_transition(cr::sys_days{cr::July / 1 / 2012}, 34s); + test_transition(cr::sys_days{cr::July / 1 / 2015}, 35s); + test_transition(cr::sys_days{cr::January / 1 / 2017}, 36s); +} + +// Tests whether the return type is the expected type. +static void test_return_type() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0ns}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0us}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0ms}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::seconds{0}}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::minutes{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::hours{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::days{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::weeks{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::months{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::years{0}}); + } +} + +int main(int, const char**) { + using namespace std::literals::chrono_literals; + std::chrono::utc_seconds time = std::chrono::utc_seconds{0s}; + static_assert(noexcept(std::chrono::tai_clock::from_utc(time))); + + test_known_values(); + test_transitions(); + test_return_type(); +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp new file mode 100644 index 000000000000000..c96ace82daca16f --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// +// +// class tai; + +// static time_point now(); + +#include +#include + +int main(int, const char**) { + using clock = std::chrono::tai_clock; + std::same_as decltype(auto) t = clock::now(); + + assert(t >= clock::time_point::min()); + assert(t <= clock::time_point::max()); +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp new file mode 100644 index 000000000000000..210f5b8a125b333 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp @@ -0,0 +1,161 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// +// +// class tai_clock; + +// static utc_time> +// to_utc(const tai_time<_Duration>& __time) noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "assert_macros.h" +#include "concat_macros.h" + +static void test_known_values() { + namespace cr = std::chrono; + using namespace std::literals::chrono_literals; + constexpr auto unix_to_tai_epoch_offset = cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + + // [time.clock.tai.overview]/1 + // ... 1958-01-01 00:00:00 TAI is equivalent to 1957-12-31 23:59:50 UTC + // ... 2000-01-01 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI + + assert(cr::tai_clock::to_utc(cr::tai_seconds{0s}) == + cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 1958} - 10s)); + + assert(cr::tai_clock::to_utc( + cr::tai_seconds{(cr::sys_days{cr::January / 1 / 2000} + unix_to_tai_epoch_offset).time_since_epoch()} + + 32s) == cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 2000})); +} + +template +static void test_leap_seconds(std::chrono::tai_time tai, + std::chrono::utc_time expected, + std::source_location loc = std::source_location::current()) { + auto utc = std::chrono::tai_clock::to_utc(tai); + TEST_REQUIRE(utc == expected, + TEST_WRITE_CONCATENATED(loc, "\nExpected output ", expected, "\nActual output ", utc, '\n')); +} + +// Tests set if existing database entries at the time of writing. +static void test_transitions() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + // "sys" is the time of the transition to the next leap second. + // "elapsed" is the number of leap seconds before the transition. + auto test_transition = [](cr::sys_days sys, cr::seconds elapsed) { + constexpr auto unix_to_tai_epoch_offset = + cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + cr::tai_seconds tai{sys.time_since_epoch() + unix_to_tai_epoch_offset + elapsed}; + + test_leap_seconds(tai - 1ns, cr::utc_clock::from_sys(sys - 1ns)); + test_leap_seconds(tai + 1s, cr::utc_clock::from_sys(sys)); + test_leap_seconds(tai + 1s + 1ns, cr::utc_clock::from_sys(sys + 1ns)); + }; + + // Transitions from the start of UTC. + test_transition(cr::sys_days{cr::July / 1 / 1972}, 10s); + test_transition(cr::sys_days{cr::January / 1 / 1973}, 11s); + test_transition(cr::sys_days{cr::January / 1 / 1974}, 12s); + test_transition(cr::sys_days{cr::January / 1 / 1975}, 13s); + test_transition(cr::sys_days{cr::January / 1 / 1976}, 14s); + test_transition(cr::sys_days{cr::January / 1 / 1977}, 15s); + test_transition(cr::sys_days{cr::January / 1 / 1978}, 16s); + test_transition(cr::sys_days{cr::January / 1 / 1979}, 17s); + test_transition(cr::sys_days{cr::January / 1 / 1980}, 18s); + test_transition(cr::sys_days{cr::July / 1 / 1981}, 19s); + test_transition(cr::sys_days{cr::July / 1 / 1982}, 20s); + test_transition(cr::sys_days{cr::July / 1 / 1983}, 21s); + test_transition(cr::sys_days{cr::July / 1 / 1985}, 22s); + test_transition(cr::sys_days{cr::January / 1 / 1988}, 23s); + test_transition(cr::sys_days{cr::January / 1 / 1990}, 24s); + test_transition(cr::sys_days{cr::January / 1 / 1991}, 25s); + test_transition(cr::sys_days{cr::July / 1 / 1992}, 26s); + test_transition(cr::sys_days{cr::July / 1 / 1993}, 27s); + test_transition(cr::sys_days{cr::July / 1 / 1994}, 28s); + test_transition(cr::sys_days{cr::January / 1 / 1996}, 29s); + test_transition(cr::sys_days{cr::July / 1 / 1997}, 30s); + test_transition(cr::sys_days{cr::January / 1 / 1999}, 31s); + test_transition(cr::sys_days{cr::January / 1 / 2006}, 32s); + test_transition(cr::sys_days{cr::January / 1 / 2009}, 33s); + test_transition(cr::sys_days{cr::July / 1 / 2012}, 34s); + test_transition(cr::sys_days{cr::July / 1 / 2015}, 35s); + test_transition(cr::sys_days{cr::January / 1 / 2017}, 36s); +} + +// Tests whether the return type is the expected type. +static void test_return_type() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{0ns}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{0us}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{0ms}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::seconds{0}}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::minutes{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::hours{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::days{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::weeks{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::months{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::years{0}}); + } +} + +int main(int, const char**) { + using namespace std::literals::chrono_literals; + + std::chrono::tai_seconds time = std::chrono::tai_seconds{0s}; + static_assert(noexcept(std::chrono::tai_clock::to_utc(time))); + + test_known_values(); + test_transitions(); + test_return_type(); +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp new file mode 100644 index 000000000000000..c4af65d447c357e --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// + +// class tai_clock { +// public: +// using rep = a signed arithmetic type; +// using period = ratio; +// using duration = chrono::duration; +// using time_point = chrono::time_point; +// static constexpr bool is_steady = unspecified; +// +// ... +// }; +// +// template +// using tai_time = time_point; +// using tai_seconds = tai_time; + +#include +#include + +#include "test_macros.h" + +// class tai_clock +using rep = std::chrono::tai_clock::rep; +using period = std::chrono::tai_clock::period; +using duration = std::chrono::tai_clock::duration; +using time_point = std::chrono::tai_clock::time_point; +constexpr bool is_steady = std::chrono::tai_clock::is_steady; + +// Tests the values. part of them are implementation defined. +LIBCPP_STATIC_ASSERT(std::same_as); +static_assert(std::is_arithmetic_v); +static_assert(std::is_signed_v); + +LIBCPP_STATIC_ASSERT(std::same_as); +static_assert(std::same_as>); + +static_assert(std::same_as>); +static_assert(std::same_as>); +LIBCPP_STATIC_ASSERT(is_steady == false); + +// typedefs +static_assert(std::same_as, std::chrono::time_point>); +static_assert(std::same_as, std::chrono::time_point>); +static_assert(std::same_as>); diff --git a/libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp b/libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp new file mode 100644 index 000000000000000..7ca088cc6e8f467 --- /dev/null +++ b/libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp @@ -0,0 +1,998 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb +// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME + +// TODO FMT This test should not require std::to_chars(floating-point) +// XFAIL: availability-fp_to_chars-missing + +// XFAIL: libcpp-has-no-experimental-tzdb +// XFAIL: availability-tzdb-missing + +// REQUIRES: locale.fr_FR.UTF-8 +// REQUIRES: locale.ja_JP.UTF-8 + +// + +// template +// struct formatter, charT>; + +#include +#include + +#include +#include +#include +#include +#include + +#include "formatter_tests.h" +#include "make_string.h" +#include "platform_support.h" // locale name macros +#include "test_macros.h" + +template +static void test_no_chrono_specs() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output + + // [time.syn] + // using nanoseconds = duration; + // using microseconds = duration; + // using milliseconds = duration; + // using seconds = duration; + // using minutes = duration>; + // using hours = duration>; + check(SV("1413-08-04 22:06:56"), SV("{}"), cr::tai_seconds(-17'179'869'184s)); // Minimum value for 35 bits. + check(SV("1889-12-12 20:45:52"), SV("{}"), cr::tai_seconds(-2'147'483'648s)); + + check(SV("1957-12-31 00:00:00"), SV("{}"), cr::tai_seconds(-24h)); + check(SV("1957-12-31 06:00:00"), SV("{}"), cr::tai_seconds(-18h)); + check(SV("1957-12-31 12:00:00"), SV("{}"), cr::tai_seconds(-12h)); + check(SV("1957-12-31 18:00:00"), SV("{}"), cr::tai_seconds(-6h)); + check(SV("1957-12-31 23:59:59"), SV("{}"), cr::tai_seconds(-1s)); + + check(SV("1958-01-01 00:00:00"), SV("{}"), cr::tai_seconds(0s)); + check(SV("1988-01-01 00:00:00"), SV("{}"), cr::tai_seconds(946'684'800s)); + check(SV("1988-01-01 01:02:03"), SV("{}"), cr::tai_seconds(946'688'523s)); + + check(SV("2026-01-19 03:14:07"), SV("{}"), cr::tai_seconds(2'147'483'647s)); + check(SV("2502-05-30 01:53:03"), SV("{}"), cr::tai_seconds(17'179'869'183s)); // Maximum value for 35 bits. + + check(SV("1988-01-01 01:02:03.123"), SV("{}"), cr::tai_time(946'688'523'123ms)); + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_year() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = + SV("{:%%C='%C'%t%%EC='%EC'%t%%y='%y'%t%%Oy='%Oy'%t%%Ey='%Ey'%t%%Y='%Y'%t%%EY='%EY'%n}"); + constexpr std::basic_string_view lfmt = + SV("{:L%%C='%C'%t%%EC='%EC'%t%%y='%y'%t%%Oy='%Oy'%t%%Ey='%Ey'%t%%Y='%Y'%t%%EY='%EY'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%C='19'\t%EC='19'\t%y='58'\t%Oy='58'\t%Ey='58'\t%Y='1958'\t%EY='1958'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%C='20'\t%EC='20'\t%y='09'\t%Oy='09'\t%Ey='09'\t%Y='2009'\t%EY='2009'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%C='19'\t%EC='19'\t%y='58'\t%Oy='58'\t%Ey='58'\t%Y='1958'\t%EY='1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%C='20'\t%EC='20'\t%y='09'\t%Oy='09'\t%Ey='09'\t%Y='2009'\t%EY='2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%C='19'\t%EC='19'\t%y='58'\t%Oy='58'\t%Ey='58'\t%Y='1958'\t%EY='1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%C='20'\t%EC='20'\t%y='09'\t%Oy='09'\t%Ey='09'\t%Y='2009'\t%EY='2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX)||defined(__FreeBSD__) + check(loc, + SV("%C='19'\t%EC='昭和'\t%y='58'\t%Oy='五十八'\t%Ey='33'\t%Y='1958'\t%EY='昭和33年'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%C='20'\t%EC='平成'\t%y='09'\t%Oy='九'\t%Ey='21'\t%Y='2009'\t%EY='平成21年'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX)||defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_month() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%b='%b'%t%%h='%h'%t%%B='%B'%t%%m='%m'%t%%Om='%Om'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%b='%b'%t%%h='%h'%t%%B='%B'%t%%m='%m'%t%%Om='%Om'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%b='Jan'\t%h='Jan'\t%B='January'\t%m='01'\t%Om='01'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%b='May'\t%h='May'\t%B='May'\t%m='05'\t%Om='05'\n"), + fmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI on Wednesday, 18 May 2033 + + // Use the global locale (fr_FR) +#if defined(__APPLE__) + check(SV("%b='jan'\t%h='jan'\t%B='janvier'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 +#else + check(SV("%b='janv.'\t%h='janv.'\t%B='janvier'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 +#endif + + check(SV("%b='mai'\t%h='mai'\t%B='mai'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI on Wednesday, 18 May 2033 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#ifdef _WIN32 + check(loc, + SV("%b='1'\t%h='1'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b='5'\t%h='5'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#elif defined(_AIX) // _WIN32 + check(loc, + SV("%b='1月'\t%h='1月'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b='5月'\t%h='5月'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#elif defined(__APPLE__) // _WIN32 + check(loc, + SV("%b=' 1'\t%h=' 1'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b=' 5'\t%h=' 5'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#elif defined(__FreeBSD__) // _WIN32 + check(loc, + SV("%b=' 1月'\t%h=' 1月'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b=' 5月'\t%h=' 5月'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#else // _WIN32 + check(loc, + SV("%b=' 1月'\t%h=' 1月'\t%B='1月'\t%m='01'\t%Om='一'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b=' 5月'\t%h=' 5月'\t%B='5月'\t%m='05'\t%Om='五'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#endif // _WIN32 + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_day() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%d='%d'%t%%Od='%Od'%t%%e='%e'%t%%Oe='%Oe'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%d='%d'%t%%Od='%Od'%t%%e='%e'%t%%Oe='%Oe'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%d='13'\t%Od='13'\t%e='13'\t%Oe='13'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%d='13'\t%Od='13'\t%e='13'\t%Oe='13'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%d='13'\t%Od='13'\t%e='13'\t%Oe='13'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%d='01'\t%Od='一'\t%e=' 1'\t%Oe='一'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%d='13'\t%Od='十三'\t%e='13'\t%Oe='十三'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_weekday() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = + SV("{:%%a='%a'%t%%A='%A'%t%%u='%u'%t%%Ou='%Ou'%t%%w='%w'%t%%Ow='%Ow'%n}"); + constexpr std::basic_string_view lfmt = + SV("{:L%%a='%a'%t%%A='%A'%t%%u='%u'%t%%Ou='%Ou'%t%%w='%w'%t%%Ow='%Ow'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%a='Wed'\t%A='Wednesday'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%a='Sun'\t%A='Sunday'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + fmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 + + // Use the global locale (fr_FR) +#if defined(__APPLE__) + check(SV("%a='mer'\t%A='Mercredi'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%a='Dim'\t%A='Dimanche'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#else + check(SV("%a='mer.'\t%A='mercredi'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%a='dim.'\t%A='dimanche'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#endif + + // Use supplied locale (ja_JP). + // This locale has a different alternate, but not on all platforms +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%a='水'\t%A='水曜日'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%a='日'\t%A='日曜日'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%a='水'\t%A='水曜日'\t%u='3'\t%Ou='三'\t%w='3'\t%Ow='三'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%a='日'\t%A='日曜日'\t%u='7'\t%Ou='七'\t%w='0'\t%Ow='〇'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_day_of_year() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%j='%j'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%j='%j'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%j='001'\n"), fmt, cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(SV("%j='138'\n"), fmt, cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use the global locale (fr_FR) + check(SV("%j='001'\n"), lfmt, cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(SV("%j='138'\n"), lfmt, cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use supplied locale (ja_JP). This locale has a different alternate. + check(loc, SV("%j='001'\n"), lfmt, cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, SV("%j='138'\n"), lfmt, cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_week() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%U='%U'%t%%OU='%OU'%t%%W='%W'%t%%OW='%OW'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%U='%U'%t%%OU='%OU'%t%%W='%W'%t%%OW='%OW'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%U='00'\t%OU='00'\t%W='00'\t%OW='00'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%U='20'\t%OU='20'\t%W='20'\t%OW='20'\n"), + fmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use the global locale (fr_FR) + check(SV("%U='00'\t%OU='00'\t%W='00'\t%OW='00'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%U='20'\t%OU='20'\t%W='20'\t%OW='20'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%U='00'\t%OU='00'\t%W='00'\t%OW='00'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%U='20'\t%OU='20'\t%W='20'\t%OW='20'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%U='00'\t%OU='〇'\t%W='00'\t%OW='〇'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%U='20'\t%OU='二十'\t%W='20'\t%OW='二十'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_iso_8601_week() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%g='%g'%t%%G='%G'%t%%V='%V'%t%%OV='%OV'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%g='%g'%t%%G='%G'%t%%V='%V'%t%%OV='%OV'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%g='58'\t%G='1958'\t%V='01'\t%OV='01'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%g='09'\t%G='2009'\t%V='07'\t%OV='07'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%g='58'\t%G='1958'\t%V='01'\t%OV='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%g='09'\t%G='2009'\t%V='07'\t%OV='07'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%g='58'\t%G='1958'\t%V='01'\t%OV='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%g='09'\t%G='2009'\t%V='07'\t%OV='07'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%g='58'\t%G='1958'\t%V='01'\t%OV='一'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%g='09'\t%G='2009'\t%V='07'\t%OV='七'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_date() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%D='%D'%t%%F='%F'%t%%x='%x'%t%%Ex='%Ex'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%D='%D'%t%%F='%F'%t%%x='%x'%t%%Ex='%Ex'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%D='01/01/58'\t%F='1958-01-01'\t%x='01/01/58'\t%Ex='01/01/58'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%D='02/13/09'\t%F='2009-02-13'\t%x='02/13/09'\t%Ex='02/13/09'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) +#if defined(__APPLE__) || defined(__FreeBSD__) + check(SV("%D='01/01/58'\t%F='1958-01-01'\t%x='01.01.1958'\t%Ex='01.01.1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%D='02/13/09'\t%F='2009-02-13'\t%x='13.02.2009'\t%Ex='13.02.2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else + check(SV("%D='01/01/58'\t%F='1958-01-01'\t%x='01/01/1958'\t%Ex='01/01/1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%D='02/13/09'\t%F='2009-02-13'\t%x='13/02/2009'\t%Ex='13/02/2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%D='01/01/58'\t%F='1958-01-01'\t%x='1958/01/01'\t%Ex='1958/01/01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%D='02/13/09'\t%F='2009-02-13'\t%x='2009/02/13'\t%Ex='2009/02/13'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%D='01/01/58'\t%F='1958-01-01'\t%x='1958年01月01日'\t%Ex='昭和33年01月01日'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%D='02/13/09'\t%F='2009-02-13'\t%x='2009年02月13日'\t%Ex='平成21年02月13日'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_time() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV( + "{:" + "%%H='%H'%t" + "%%OH='%OH'%t" + "%%I='%I'%t" + "%%OI='%OI'%t" + "%%M='%M'%t" + "%%OM='%OM'%t" + "%%S='%S'%t" + "%%OS='%OS'%t" + "%%p='%p'%t" + "%%R='%R'%t" + "%%T='%T'%t" + "%%r='%r'%t" + "%%X='%X'%t" + "%%EX='%EX'%t" + "%n}"); + constexpr std::basic_string_view lfmt = SV( + "{:L" + "%%H='%H'%t" + "%%OH='%OH'%t" + "%%I='%I'%t" + "%%OI='%OI'%t" + "%%M='%M'%t" + "%%OM='%OM'%t" + "%%S='%S'%t" + "%%OS='%OS'%t" + "%%p='%p'%t" + "%%R='%R'%t" + "%%T='%T'%t" + "%%r='%r'%t" + "%%X='%X'%t" + "%%EX='%EX'%t" + "%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%H='00'\t" + "%OH='00'\t" + "%I='12'\t" + "%OI='12'\t" + "%M='00'\t" + "%OM='00'\t" + "%S='00'\t" + "%OS='00'\t" + "%p='AM'\t" + "%R='00:00'\t" + "%T='00:00:00'\t" + "%r='12:00:00 AM'\t" + "%X='00:00:00'\t" + "%EX='00:00:00'\t" + "\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%H='23'\t" + "%OH='23'\t" + "%I='11'\t" + "%OI='11'\t" + "%M='31'\t" + "%OM='31'\t" + "%S='30.123'\t" + "%OS='30.123'\t" + "%p='PM'\t" + "%R='23:31'\t" + "%T='23:31:30.123'\t" + "%r='11:31:30 PM'\t" + "%X='23:31:30'\t" + "%EX='23:31:30'\t" + "\n"), + fmt, + cr::tai_time(1'613'259'090'123ms)); // 23:31:30 TAI Friday, 13 February 2009 + // Use the global locale (fr_FR) + check(SV("%H='00'\t" + "%OH='00'\t" + "%I='12'\t" + "%OI='12'\t" + "%M='00'\t" + "%OM='00'\t" + "%S='00'\t" + "%OS='00'\t" +#if defined(_AIX) + "%p='AM'\t" +#else + "%p=''\t" +#endif + "%R='00:00'\t" + "%T='00:00:00'\t" +#ifdef _WIN32 + "%r='00:00:00'\t" +#elif defined(_AIX) + "%r='12:00:00 AM'\t" +#elif defined(__APPLE__) || defined(__FreeBSD__) + "%r=''\t" +#else + "%r='12:00:00 '\t" +#endif + "%X='00:00:00'\t" + "%EX='00:00:00'\t" + "\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%H='23'\t" + "%OH='23'\t" + "%I='11'\t" + "%OI='11'\t" + "%M='31'\t" + "%OM='31'\t" + "%S='30,123'\t" + "%OS='30,123'\t" +#if defined(_AIX) + "%p='PM'\t" +#else + "%p=''\t" +#endif + "%R='23:31'\t" + "%T='23:31:30,123'\t" +#ifdef _WIN32 + "%r='23:31:30'\t" +#elif defined(_AIX) + "%r='11:31:30 PM'\t" +#elif defined(__APPLE__) || defined(__FreeBSD__) + "%r=''\t" +#else + "%r='11:31:30 '\t" +#endif + "%X='23:31:30'\t" + "%EX='23:31:30'\t" + "\n"), + lfmt, + cr::tai_time(1'613'259'090'123ms)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) + check(loc, + SV("%H='00'\t" + "%OH='00'\t" + "%I='12'\t" + "%OI='12'\t" + "%M='00'\t" + "%OM='00'\t" + "%S='00'\t" + "%OS='00'\t" +# if defined(__APPLE__) + "%p='AM'\t" +# else + "%p='午前'\t" +# endif + "%R='00:00'\t" + "%T='00:00:00'\t" +# if defined(__APPLE__) || defined(__FreeBSD__) +# if defined(__APPLE__) + "%r='12:00:00 AM'\t" +# else + "%r='12:00:00 午前'\t" +# endif + "%X='00時00分00秒'\t" + "%EX='00時00分00秒'\t" +# elif defined(_WIN32) + "%r='0:00:00'\t" + "%X='0:00:00'\t" + "%EX='0:00:00'\t" +# else + "%r='午前12:00:00'\t" + "%X='00:00:00'\t" + "%EX='00:00:00'\t" +# endif + "\n"), + lfmt, + cr::hh_mm_ss(0s)); + + check(loc, + SV("%H='23'\t" + "%OH='23'\t" + "%I='11'\t" + "%OI='11'\t" + "%M='31'\t" + "%OM='31'\t" + "%S='30.123'\t" + "%OS='30.123'\t" +# if defined(__APPLE__) + "%p='PM'\t" +# else + "%p='午後'\t" +# endif + "%R='23:31'\t" + "%T='23:31:30.123'\t" +# if defined(__APPLE__) || defined(__FreeBSD__) +# if defined(__APPLE__) + "%r='11:31:30 PM'\t" +# else + "%r='11:31:30 午後'\t" +# endif + "%X='23時31分30秒'\t" + "%EX='23時31分30秒'\t" +# elif defined(_WIN32) + "%r='23:31:30'\t" + "%X='23:31:30'\t" + "%EX='23:31:30'\t" +# else + "%r='午後11:31:30'\t" + "%X='23:31:30'\t" + "%EX='23:31:30'\t" +# endif + "\n"), + lfmt, + cr::hh_mm_ss(23h + 31min + 30s + 123ms)); +#else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) + check(loc, + SV("%H='00'\t" + "%OH='〇'\t" + "%I='12'\t" + "%OI='十二'\t" + "%M='00'\t" + "%OM='〇'\t" + "%S='00'\t" + "%OS='〇'\t" + "%p='午前'\t" + "%R='00:00'\t" + "%T='00:00:00'\t" + "%r='午前12時00分00秒'\t" + "%X='00時00分00秒'\t" + "%EX='00時00分00秒'\t" + "\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%H='23'\t" + "%OH='二十三'\t" + "%I='11'\t" + "%OI='十一'\t" + "%M='31'\t" + "%OM='三十一'\t" + "%S='30.123'\t" + "%OS='三十.123'\t" + "%p='午後'\t" + "%R='23:31'\t" + "%T='23:31:30.123'\t" + "%r='午後11時31分30秒'\t" + "%X='23時31分30秒'\t" + "%EX='23時31分30秒'\t" + "\n"), + lfmt, + cr::tai_time(1'613'259'090'123ms)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_date_time() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%c='%c'%t%%Ec='%Ec'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%c='%c'%t%%Ec='%Ec'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%c='Wed Jan 1 00:00:00 1958'\t%Ec='Wed Jan 1 00:00:00 1958'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%c='Fri Feb 13 23:31:30 2009'\t%Ec='Fri Feb 13 23:31:30 2009'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check( +// https://sourceware.org/bugzilla/show_bug.cgi?id=24054 +#if defined(__powerpc__) && defined(__linux__) + SV("%c='mer. 01 janv. 1958 00:00:00 TAI'\t%Ec='mer. 01 janv. 1958 00:00:00 TAI'\n"), +#elif defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29 + SV("%c='mer. 01 janv. 1958 00:00:00 GMT'\t%Ec='mer. 01 janv. 1958 00:00:00 GMT'\n"), +#elif defined(_AIX) + SV("%c=' 1 janvier 1958 à 00:00:00 TAI'\t%Ec=' 1 janvier 1958 à 00:00:00 TAI'\n"), +#elif defined(__APPLE__) + SV("%c='Jeu 1 jan 00:00:00 1958'\t%Ec='Jeu 1 jan 00:00:00 1958'\n"), +#elif defined(_WIN32) + SV("%c='01/01/1958 00:00:00'\t%Ec='01/01/1958 00:00:00'\n"), +#elif defined(__FreeBSD__) + SV("%c='mer. 1 janv. 00:00:00 1958'\t%Ec='mer. 1 janv. 00:00:00 1958'\n"), +#else + SV("%c='mer. 01 janv. 1958 00:00:00'\t%Ec='mer. 01 janv. 1958 00:00:00'\n"), +#endif + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check( +// https://sourceware.org/bugzilla/show_bug.cgi?id=24054 +#if defined(__powerpc__) && defined(__linux__) + SV("%c='ven. 13 févr. 2009 23:31:30 TAI'\t%Ec='ven. 13 févr. 2009 23:31:30 TAI'\n"), +#elif defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29 + SV("%c='ven. 13 févr. 2009 23:31:30 GMT'\t%Ec='ven. 13 févr. 2009 23:31:30 GMT'\n"), +#elif defined(_AIX) + SV("%c='13 février 2009 à 23:31:30 TAI'\t%Ec='13 février 2009 à 23:31:30 TAI'\n"), +#elif defined(__APPLE__) + SV("%c='Ven 13 fév 23:31:30 2009'\t%Ec='Ven 13 fév 23:31:30 2009'\n"), +#elif defined(_WIN32) + SV("%c='13/02/2009 23:31:30'\t%Ec='13/02/2009 23:31:30'\n"), +#elif defined(__FreeBSD__) + SV("%c='ven. 13 févr. 23:31:30 2009'\t%Ec='ven. 13 févr. 23:31:30 2009'\n"), +#else + SV("%c='ven. 13 févr. 2009 23:31:30'\t%Ec='ven. 13 févr. 2009 23:31:30'\n"), +#endif + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate.a +#if defined(__APPLE__) || defined(__FreeBSD__) + check(loc, + SV("%c='水 1/ 1 00:00:00 1958'\t%Ec='水 1/ 1 00:00:00 1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, + SV("%c='金 2/13 23:31:30 2009'\t%Ec='金 2/13 23:31:30 2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#elif defined(_AIX) // defined(__APPLE__)|| defined(__FreeBSD__) + check(loc, + SV("%c='1958年01月 1日 00:00:00 TAI'\t%Ec='1958年01月 1日 00:00:00 TAI'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, + SV("%c='2009年02月13日 23:31:30 TAI'\t%Ec='2009年02月13日 23:31:30 TAI'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#elif defined(_WIN32) // defined(__APPLE__)|| defined(__FreeBSD__) + check(loc, + SV("%c='1958/01/01 0:00:00'\t%Ec='1958/01/01 0:00:00'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, + SV("%c='2009/02/13 23:31:30'\t%Ec='2009/02/13 23:31:30'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(__APPLE__)|| defined(__FreeBSD__) + check(loc, + SV("%c='1958年01月01日 00時00分00秒'\t%Ec='昭和33年01月01日 00時00分00秒'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%c='2009年02月13日 23時31分30秒'\t%Ec='平成21年02月13日 23時31分30秒'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(__APPLE__)|| defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_time_zone() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%z='%z'%t%%Ez='%Ez'%t%%Oz='%Oz'%t%%Z='%Z'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%z='%z'%t%%Ez='%Ez'%t%%Oz='%Oz'%t%%Z='%Z'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='TAI'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + // Use the global locale (fr_FR) + check(SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='TAI'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + // Use supplied locale (ja_JP). + check(loc, + SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='TAI'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values() { + test_valid_values_year(); + test_valid_values_month(); + test_valid_values_day(); + test_valid_values_weekday(); + test_valid_values_day_of_year(); + test_valid_values_week(); + test_valid_values_iso_8601_week(); + test_valid_values_date(); + test_valid_values_time(); + test_valid_values_date_time(); + test_valid_values_time_zone(); +} + +template +static void test() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + test_no_chrono_specs(); + test_valid_values(); + check_invalid_types( + {SV("a"), SV("A"), SV("b"), SV("B"), SV("c"), SV("C"), SV("d"), SV("D"), SV("e"), SV("F"), SV("g"), + SV("G"), SV("h"), SV("H"), SV("I"), SV("j"), SV("m"), SV("M"), SV("p"), SV("r"), SV("R"), SV("S"), + SV("T"), SV("u"), SV("U"), SV("V"), SV("w"), SV("W"), SV("x"), SV("X"), SV("y"), SV("Y"), SV("z"), + SV("Z"), SV("Ec"), SV("EC"), SV("Ex"), SV("EX"), SV("Ey"), SV("EY"), SV("Ez"), SV("Od"), SV("Oe"), SV("OH"), + SV("OI"), SV("Om"), SV("OM"), SV("OS"), SV("Ou"), SV("OU"), SV("OV"), SV("Ow"), SV("OW"), SV("Oy"), SV("Oz")}, + cr::tai_seconds(0s)); + + check_exception("The format specifier expects a '%' or a '}'", SV("{:A"), cr::tai_seconds(0s)); + check_exception("The chrono specifiers contain a '{'", SV("{:%%{"), cr::tai_seconds(0s)); + check_exception("End of input while parsing a conversion specifier", SV("{:%"), cr::tai_seconds(0s)); + check_exception("End of input while parsing the modifier E", SV("{:%E"), cr::tai_seconds(0s)); + check_exception("End of input while parsing the modifier O", SV("{:%O"), cr::tai_seconds(0s)); + + // Precision not allowed + check_exception("The format specifier expects a '%' or a '}'", SV("{:.3}"), cr::tai_seconds(0s)); +} + +int main(int, char**) { + test(); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + + return 0; +} diff --git a/libcxx/test/support/concat_macros.h b/libcxx/test/support/concat_macros.h index d7340b8faf6e562..50b656219739273 100644 --- a/libcxx/test/support/concat_macros.h +++ b/libcxx/test/support/concat_macros.h @@ -11,6 +11,7 @@ #include #include +#include #include "assert_macros.h" #include "test_macros.h" @@ -134,6 +135,10 @@ OutIt test_transcode(InIt first, InIt last, OutIt out_it) { return out_it; } +std::ostream& operator<<(std::ostream& os, const std::source_location& loc) { + return os << loc.file_name() << ':' << loc.line() << ':' << loc.column(); +} + template concept test_streamable = requires(std::stringstream& stream, T&& value) { stream << value; }; From libcxx-commits at lists.llvm.org Mon Feb 3 10:09:45 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Mon, 03 Feb 2025 10:09:45 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) In-Reply-To: Message-ID: <67a10669.170a0220.23e8cf.4421@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-libcxx Author: Mark de Wever (mordante)
Changes Implements parts of: - P0355 Extending <chrono> to Calendars and Time Zones - P1361 Integration of chrono with text formatting - LWG3359 <chrono> leap second support should allow for negative leap seconds --- Patch is 78.95 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/125550.diff 17 Files Affected: - (modified) libcxx/docs/Status/FormatPaper.csv (+1-1) - (modified) libcxx/include/CMakeLists.txt (+1) - (modified) libcxx/include/__chrono/convert_to_tm.h (+13) - (modified) libcxx/include/__chrono/formatter.h (+14) - (modified) libcxx/include/__chrono/ostream.h (+7) - (added) libcxx/include/__chrono/tai_clock.h (+98) - (modified) libcxx/include/chrono (+31) - (modified) libcxx/include/module.modulemap (+4) - (modified) libcxx/modules/std/chrono.inc (+1-1) - (modified) libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp (+11) - (added) libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp (+164) - (added) libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp (+159) - (added) libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp (+30) - (added) libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp (+161) - (added) libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp (+59) - (added) libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp (+998) - (modified) libcxx/test/support/concat_macros.h (+5) ``````````diff diff --git a/libcxx/docs/Status/FormatPaper.csv b/libcxx/docs/Status/FormatPaper.csv index 343fa62f135654..de64e9c25a7771 100644 --- a/libcxx/docs/Status/FormatPaper.csv +++ b/libcxx/docs/Status/FormatPaper.csv @@ -3,7 +3,7 @@ Section,Description,Dependencies,Assignee,Status,First released version `[time.syn] `_,"Formatter ``chrono::duration``",,Mark de Wever,|Complete|,16 `[time.syn] `_,"Formatter ``chrono::sys_time``",,Mark de Wever,|Complete|,17 `[time.syn] `_,"Formatter ``chrono::utc_time``",A ```` implementation,Mark de Wever,|Complete|,20 -`[time.syn] `_,"Formatter ``chrono::tai_time``",A ```` implementation,Mark de Wever,,, ++`[time.syn] `_,"Formatter ``chrono::tai_time``",,Mark de Wever,|Complete|,21 `[time.syn] `_,"Formatter ``chrono::gps_time``",A ```` implementation,Mark de Wever,,, `[time.syn] `_,"Formatter ``chrono::file_time``",,Mark de Wever,|Complete|,17 `[time.syn] `_,"Formatter ``chrono::local_time``",,Mark de Wever,|Complete|,17 diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8dac823503d73f..ce805b4eb7b8b4 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -270,6 +270,7 @@ set(files __chrono/steady_clock.h __chrono/sys_info.h __chrono/system_clock.h + __chrono/tai_clock.h __chrono/time_point.h __chrono/time_zone.h __chrono/time_zone_link.h diff --git a/libcxx/include/__chrono/convert_to_tm.h b/libcxx/include/__chrono/convert_to_tm.h index 7d06a38d87f26d..934293ce382345 100644 --- a/libcxx/include/__chrono/convert_to_tm.h +++ b/libcxx/include/__chrono/convert_to_tm.h @@ -23,6 +23,7 @@ #include <__chrono/statically_widen.h> #include <__chrono/sys_info.h> #include <__chrono/system_clock.h> +#include <__chrono/tai_clock.h> #include <__chrono/time_point.h> #include <__chrono/utc_clock.h> #include <__chrono/weekday.h> @@ -112,6 +113,16 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::utc_time<_Duration> __tp) { return __result; } +template +_LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::tai_time<_Duration> __tp) { + using _Rp = common_type_t<_Duration, chrono::seconds>; + // The time between the TAI epoch (1958-01-01) and UNIX epoch (1970-01-01). + // This avoids leap second conversion when going from TAI to UTC. + // (It also avoids issues when the date is before the UTC epoch.) + constexpr chrono::seconds __offset{4383 * 24 * 60 * 60}; + return std::__convert_to_tm<_Tm>(chrono::sys_time<_Rp>{__tp.time_since_epoch() - __offset}); +} + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION @@ -131,6 +142,8 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) { # if _LIBCPP_HAS_EXPERIMENTAL_TZDB else if constexpr (same_as) return std::__convert_to_tm<_Tm>(__value); + else if constexpr (same_as) + return std::__convert_to_tm<_Tm>(__value); # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION else if constexpr (same_as) diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h index d17acd274e4cda..753a824a3c50d7 100644 --- a/libcxx/include/__chrono/formatter.h +++ b/libcxx/include/__chrono/formatter.h @@ -31,6 +31,7 @@ # include <__chrono/statically_widen.h> # include <__chrono/sys_info.h> # include <__chrono/system_clock.h> +# include <__chrono/tai_clock.h> # include <__chrono/time_point.h> # include <__chrono/utc_clock.h> # include <__chrono/weekday.h> @@ -231,6 +232,8 @@ _LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const # if _LIBCPP_HAS_EXPERIMENTAL_TZDB if constexpr (same_as<_Tp, chrono::sys_info>) return {__value.abbrev, __value.offset}; + else if constexpr (__is_time_point<_Tp> && requires { requires same_as; }) + return {"TAI", chrono::seconds{0}}; # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) return __formatter::__convert_to_time_zone(__value.get_info()); @@ -734,6 +737,17 @@ struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : pub } }; +template +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : public __formatter_chrono<_CharT> { +public: + using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); + } +}; + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM diff --git a/libcxx/include/__chrono/ostream.h b/libcxx/include/__chrono/ostream.h index ed9ad8e346ba94..b8cd6a4680662b 100644 --- a/libcxx/include/__chrono/ostream.h +++ b/libcxx/include/__chrono/ostream.h @@ -26,6 +26,7 @@ # include <__chrono/statically_widen.h> # include <__chrono/sys_info.h> # include <__chrono/system_clock.h> +# include <__chrono/tai_clock.h> # include <__chrono/utc_clock.h> # include <__chrono/weekday.h> # include <__chrono/year.h> @@ -71,6 +72,12 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const utc_time<_Duration>& __tp return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); } +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const tai_time<_Duration>& __tp) { + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); +} + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM diff --git a/libcxx/include/__chrono/tai_clock.h b/libcxx/include/__chrono/tai_clock.h new file mode 100644 index 00000000000000..18ba329b7b8fb4 --- /dev/null +++ b/libcxx/include/__chrono/tai_clock.h @@ -0,0 +1,98 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_TAI_CLOCK_H +#define _LIBCPP___CHRONO_TAI_CLOCK_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if _LIBCPP_HAS_EXPERIMENTAL_TZDB + +# include <__chrono/duration.h> +# include <__chrono/time_point.h> +# include <__chrono/utc_clock.h> +# include <__config> +# include <__type_traits/common_type.h> + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION + +namespace chrono { + +class tai_clock; + +template +using tai_time = time_point; +using tai_seconds = tai_time; + +// [time.clock.tai.overview]/1 +// The clock tai_clock measures seconds since 1958-01-01 00:00:00 and is +// offset 10s ahead of UTC at this date. That is, 1958-01-01 00:00:00 TAI is +// equivalent to 1957-12-31 23:59:50 UTC. Leap seconds are not inserted into +// TAI. Therefore every time a leap second is inserted into UTC, UTC shifts +// another second with respect to TAI. For example by 2000-01-01 there had +// been 22 positive and 0 negative leap seconds inserted so 2000-01-01 +// 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI (22s plus the +// initial 10s offset). +// +// Note this does not specify what the UTC offset before 1958-01-01 00:00:00 +// TAI is. However the member functions are fully specified in the standard. +// https://koka-lang.github.io/koka/doc/std_time_utc.html contains more +// information and references. +class tai_clock { +public: + using rep = utc_clock::rep; + using period = utc_clock::period; + using duration = chrono::duration; + using time_point = chrono::time_point; + static constexpr bool is_steady = false; // The utc_clock is not steady. + + // The static difference between UTC and TAI time. + static constexpr chrono::seconds __offset{378691210}; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static time_point now() { return from_utc(utc_clock::now()); } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static utc_time> + to_utc(const tai_time<_Duration>& __time) noexcept { + using _Rp = common_type_t<_Duration, seconds>; + _Duration __time_since_epoch = __time.time_since_epoch(); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch >= utc_time<_Rp>::min().time_since_epoch() + __offset, + "the TAI to UTC conversion would underflow"); + + return utc_time<_Rp>{__time_since_epoch - __offset}; + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static tai_time> + from_utc(const utc_time<_Duration>& __time) noexcept { + using _Rp = common_type_t<_Duration, seconds>; + _Duration __time_since_epoch = __time.time_since_epoch(); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch <= utc_time<_Rp>::max().time_since_epoch() - __offset, + "the UTC to TAI conversion would overflow"); + + return tai_time<_Rp>{__time_since_epoch + __offset}; + } +}; + +} // namespace chrono + +# endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && + // _LIBCPP_HAS_LOCALIZATION + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB + +#endif // _LIBCPP___CHRONO_TAI_CLOCK_H diff --git a/libcxx/include/chrono b/libcxx/include/chrono index 10695eea649fb7..bd4c98600440c4 100644 --- a/libcxx/include/chrono +++ b/libcxx/include/chrono @@ -335,6 +335,34 @@ struct leap_second_info { // C++20 template // C++20 leap_second_info get_leap_second_info(const utc_time& ut); + +// [time.clock.tai], class tai_clock +class tai_clock { // C++20 +public: + using rep = a signed arithmetic type; + using period = ratio; + using duration = chrono::duration; + using time_point = chrono::time_point; + static constexpr bool is_steady = unspecified; + + static time_point now(); + + template + static utc_time> + to_utc(const tai_time& t); + template + static tai_time> + from_utc(const utc_time& t); +}; + +template +using tai_time = time_point; // C++20 +using tai_seconds = tai_time; // C++20 + +template // C++20 + basic_ostream& + operator<<(basic_ostream& os, const tai_time& t); + class file_clock // C++20 { public: @@ -898,6 +926,8 @@ namespace std { struct formatter, charT>; // C++20 template struct formatter, charT>; // C++20 + template + struct formatter, charT>; // C++20 template struct formatter, charT>; // C++20 template @@ -1014,6 +1044,7 @@ constexpr chrono::year operator ""y(unsigned lo # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION # include <__chrono/leap_second.h> +# include <__chrono/tai_clock.h> # include <__chrono/time_zone.h> # include <__chrono/time_zone_link.h> # include <__chrono/tzdb.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4bae02137b37b2..fd39c946b992a4 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -967,6 +967,10 @@ module std [system] { header "__chrono/system_clock.h" export std.chrono.time_point } + module tai_clock { + header "__chrono/tai_clock.h" + export std.chrono.time_point + } module time_point { header "__chrono/time_point.h" } module time_zone_link { header "__chrono/time_zone_link.h" } module time_zone { header "__chrono/time_zone.h" } diff --git a/libcxx/modules/std/chrono.inc b/libcxx/modules/std/chrono.inc index 98f14f716c2078..43e8da36e90448 100644 --- a/libcxx/modules/std/chrono.inc +++ b/libcxx/modules/std/chrono.inc @@ -97,13 +97,13 @@ export namespace std { using std::chrono::get_leap_second_info; -# if 0 // [time.clock.tai], class tai_clock using std::chrono::tai_clock; using std::chrono::tai_seconds; using std::chrono::tai_time; +# if 0 // [time.clock.gps], class gps_clock using std::chrono::gps_clock; diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp index 644c5b598c018d..bb40e0cfc4e1b8 100644 --- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp +++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp @@ -102,4 +102,15 @@ void test(std::chrono::time_zone tz, std::chrono::time_zone_link link, std::chro zt.get_sys_time(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} zt.get_info(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} } + + { // [time.clock.tai] + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::now(); + + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::to_utc(std::chrono::tai_seconds{}); + + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::from_utc(std::chrono::utc_seconds{}); + } } diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp new file mode 100644 index 00000000000000..3508ceb8b2d3f6 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp @@ -0,0 +1,164 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb +// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME + +// TODO FMT This test should not require std::to_chars(floating-point) +// XFAIL: availability-fp_to_chars-missing + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// REQUIRES: locale.fr_FR.UTF-8 +// REQUIRES: locale.ja_JP.UTF-8 + +// + +// class taitem_clock; + +// template +// basic_ostream& +// operator<<(basic_ostream& os, const tai_time& tp); + +#include +#include +#include +#include + +#include "make_string.h" +#include "platform_support.h" // locale name macros +#include "test_macros.h" + +#define SV(S) MAKE_STRING_VIEW(CharT, S) + +template +static std::basic_string stream_c_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static std::basic_string stream_fr_FR_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + const std::locale locale(LOCALE_fr_FR_UTF_8); + sstr.imbue(locale); + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static std::basic_string stream_ja_JP_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + const std::locale locale(LOCALE_ja_JP_UTF_8); + sstr.imbue(locale); + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static void test_c() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + assert(stream_c_locale(cr::tai_time{946'688'523'123'456'789ns}) == + SV("1988-01-01 01:02:03.123456789")); + assert(stream_c_locale(cr::tai_time{946'688'523'123'456us}) == + SV("1988-01-01 01:02:03.123456")); + + assert(stream_c_locale(cr::tai_time{946'684'822'123ms}) == SV("1988-01-01 00:00:22.123")); + assert(stream_c_locale(cr::tai_seconds{1'234'567'890s}) == SV("1997-02-13 23:31:30")); + assert(stream_c_locale(cr::tai_time{20'576'131min}) == SV("1997-02-13 23:31:00")); + assert(stream_c_locale(cr::tai_time{342'935h}) == SV("1997-02-13 23:00:00")); + + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{60}}) == SV("1958-01-01 00:02:00")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:30:00.0")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:15:00.00")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{36611}}) == SV("1958-01-01 01:01:01.1")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{12'345'678'9010}}) == SV("1997-02-13 23:31:30.10")); +} + +template +static void test_fr_FR() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + assert(stream_fr_FR_locale(cr::tai_time{946'688'523'123'456'789ns}) == + SV("1988-01-01 01:02:03,123456789")); + assert(stream_fr_FR_locale(cr::tai_time{946'688'523'123'456us}) == + SV("1988-01-01 01:02:03,123456")); + + assert(stream_fr_FR_locale(cr::tai_time{946'684'822'123ms}) == + SV("1988-01-01 00:00:22,123")); + assert(str... [truncated] ``````````
https://github.com/llvm/llvm-project/pull/125550 From libcxx-commits at lists.llvm.org Mon Feb 3 10:11:20 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:11:20 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Decrease instantiation cost of __constexpr_memmove (PR #125109) In-Reply-To: Message-ID: <67a106c8.170a0220.3588da.f0ae@mx.google.com> https://github.com/mordante edited https://github.com/llvm/llvm-project/pull/125109 From libcxx-commits at lists.llvm.org Mon Feb 3 10:16:22 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:16:22 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Decrease instantiation cost of __constexpr_memmove (PR #125109) In-Reply-To: Message-ID: <67a107f6.170a0220.392620.ae91@mx.google.com> https://github.com/mordante approved this pull request. Thanks, LGTM! Just curious, do you have any numbers on the compilation performance improvement? FYI I fixed a minor typo in `never` in the commit message. https://github.com/llvm/llvm-project/pull/125109 From libcxx-commits at lists.llvm.org Mon Feb 3 10:32:23 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:32:23 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix basic_string not allowing max_size() elements to be stored (PR #125423) In-Reply-To: Message-ID: <67a10bb7.170a0220.15e541.f834@mx.google.com> https://github.com/mordante commented: In general happy with the fix, one comment. https://github.com/llvm/llvm-project/pull/125423 From libcxx-commits at lists.llvm.org Mon Feb 3 10:32:24 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:32:24 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix basic_string not allowing max_size() elements to be stored (PR #125423) In-Reply-To: Message-ID: <67a10bb8.050a0220.2feeea.4bbe@mx.google.com> ================ @@ -1305,10 +1305,10 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type max_size() const _NOEXCEPT { size_type __m = __alloc_traits::max_size(__alloc_); if (__m <= std::numeric_limits::max() / 2) { - return __m - __alignment; + return __m - __alignment - 1; } else { bool __uses_lsb = __endian_factor == 2; - return __uses_lsb ? __m - __alignment : (__m / 2) - __alignment; + return __uses_lsb ? __m - __alignment - 1 : (__m / 2) - __alignment - 1; ---------------- mordante wrote: Since this is an observable change I'd like a note in the release notes. https://github.com/llvm/llvm-project/pull/125423 From libcxx-commits at lists.llvm.org Mon Feb 3 10:32:24 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:32:24 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix basic_string not allowing max_size() elements to be stored (PR #125423) In-Reply-To: Message-ID: <67a10bb8.a70a0220.33abff.202d@mx.google.com> https://github.com/mordante edited https://github.com/llvm/llvm-project/pull/125423 From libcxx-commits at lists.llvm.org Mon Feb 3 10:51:26 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:51:26 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Implement generic associative container benchmarks (PR #123663) In-Reply-To: Message-ID: <67a1102e.170a0220.30b866.f4bc@mx.google.com> https://github.com/mordante commented: Thanks for working on this! In general happy, just a few comments. https://github.com/llvm/llvm-project/pull/123663 From libcxx-commits at lists.llvm.org Mon Feb 3 10:51:26 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:51:26 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Implement generic associative container benchmarks (PR #123663) In-Reply-To: Message-ID: <67a1102e.050a0220.18efbf.73de@mx.google.com> https://github.com/mordante edited https://github.com/llvm/llvm-project/pull/123663 From libcxx-commits at lists.llvm.org Mon Feb 3 10:51:26 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:51:26 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Implement generic associative container benchmarks (PR #123663) In-Reply-To: Message-ID: <67a1102e.170a0220.21332e.4dac@mx.google.com> ================ @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +#include ---------------- mordante wrote: Since this file is new I wonder, should we add test for the unordered associative containers? https://github.com/llvm/llvm-project/pull/123663 From libcxx-commits at lists.llvm.org Mon Feb 3 10:51:26 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:51:26 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Implement generic associative container benchmarks (PR #123663) In-Reply-To: Message-ID: <67a1102e.170a0220.3668a2.ffb8@mx.google.com> ================ @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 ---------------- mordante wrote: ```suggestion // REQUIRES: std-at-least-c++26 ``` This patch has landed :-) https://github.com/llvm/llvm-project/pull/123663 From libcxx-commits at lists.llvm.org Mon Feb 3 10:51:26 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:51:26 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Implement generic associative container benchmarks (PR #123663) In-Reply-To: Message-ID: <67a1102e.170a0220.27407a.5330@mx.google.com> ================ @@ -6,944 +6,20 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 ---------------- mordante wrote: Can you explain in the commit message why we're no longer able to test with C++17. I don't mind the change, but I like to have the reason documented. https://github.com/llvm/llvm-project/pull/123663 From libcxx-commits at lists.llvm.org Mon Feb 3 10:51:27 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 10:51:27 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Implement generic associative container benchmarks (PR #123663) In-Reply-To: Message-ID: <67a1102f.170a0220.2f6d28.f463@mx.google.com> ================ @@ -0,0 +1,536 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_BENCHMARKS_CONTAINERS_ASSOCIATIVE_CONTAINER_BENCHMARKS_H +#define TEST_BENCHMARKS_CONTAINERS_ASSOCIATIVE_CONTAINER_BENCHMARKS_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "../GenerateInput.h" +#include "test_macros.h" + +namespace support { + +template +struct adapt_operations; + +template +struct adapt_operations> { + using ValueType = typename std::set::value_type; + using KeyType = typename std::set::key_type; + static ValueType value_from_key(KeyType const& k) { return k; } + static KeyType key_from_value(ValueType const& value) { return value; } +}; + +template +struct adapt_operations> { + using ValueType = typename std::map::value_type; + using KeyType = typename std::map::key_type; + static ValueType value_from_key(KeyType const& k) { return {k, Generate::arbitrary()}; } + static KeyType key_from_value(ValueType const& value) { return value.first; } +}; + +#if TEST_STD_VER >= 26 +template +struct adapt_operations> { + using ValueType = typename std::map::value_type; + using KeyType = typename std::map::key_type; + static ValueType value_from_key(KeyType const& k) { return {k, Generate::arbitrary()}; } + static KeyType key_from_value(ValueType const& value) { return value.first; } +}; +#endif + +template +void associative_container_benchmarks(std::string container) { + using Key = typename Container::key_type; + using Value = typename Container::value_type; + + auto generate_unique_keys = [=](std::size_t n) { + std::set keys; + while (keys.size() < n) { + Key k = Generate::random(); + keys.insert(k); + } + return std::vector(keys.begin(), keys.end()); + }; + + auto add_dummy_mapped_type = [](std::vector const& keys) { + std::vector kv; + for (Key const& k : keys) + kv.push_back(adapt_operations::value_from_key(k)); + return kv; + }; + + auto get_key = [](Value const& v) { return adapt_operations::key_from_value(v); }; + + // These benchmarks are structured to perform the operation being benchmarked + // a small number of times at each iteration, in order to offset the cost of + // PauseTiming() and ResumeTiming(). + static constexpr std::size_t BatchSize = 10; + + struct ScratchSpace { + char storage[sizeof(Container)]; ---------------- mordante wrote: We should make sure the storage is properly aligned. https://github.com/llvm/llvm-project/pull/123663 From libcxx-commits at lists.llvm.org Mon Feb 3 11:09:41 2025 From: libcxx-commits at lists.llvm.org (=?UTF-8?B?0JTQvNC40YLRgNC40Lkg0JjQt9Cy0L7Qu9C+0LI=?= via libcxx-commits) Date: Mon, 03 Feb 2025 11:09:41 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Support `constexpr` for `std::stable_sort` in radix sort branch (PR #125284) In-Reply-To: Message-ID: <67a11475.170a0220.388e38.fad9@mx.google.com> ================ @@ -253,6 +253,12 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort( if constexpr (__allowed_radix_sort) { if (__len <= __buff_size && __len >= static_cast(__radix_sort_min_bound()) && __len <= static_cast(__radix_sort_max_bound())) { + for (auto* __p = __buff; __p < __buff + __buff_size; ++__p) { + std::__construct_at(__p, 0); + } + __destruct_n __d(__buff_size); + unique_ptr __h2(__buff, __d); ---------------- izvolov wrote: Yes, you're right. Done all three things. https://github.com/llvm/llvm-project/pull/125284 From libcxx-commits at lists.llvm.org Mon Feb 3 11:23:49 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 11:23:49 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <67a117c5.170a0220.27fbdc.01cf@mx.google.com> https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/107197 >From 0db3132b818ba1fd1f8d5b5d684e5170d31375df Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Tue, 3 Sep 2024 19:39:17 +0200 Subject: [PATCH] [libc++] Add basic constant folding for std::format --- libcxx/include/__config | 8 ++++ libcxx/include/__format/format_functions.h | 41 +++++++++++++++++++ .../test/benchmarks/format/format.bench.cpp | 9 ++++ 3 files changed, 58 insertions(+) diff --git a/libcxx/include/__config b/libcxx/include/__config index 1c6dd8f36c32f2..a7c857aec2e9bb 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -556,6 +556,13 @@ typedef __char32_t char32_t; # define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++2b-extensions") # endif +# if __has_warning("-Wc++23-lambda-attributes") +# define _LIBCPP_CLANG_DIANGOSTIC_INGORED_CXX23_LAMBDA_ATTRIBUTES \ + _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++23-lambda-attributes") +# else +# define _LIBCPP_CLANG_DIANGOSTIC_INGORED_CXX23_LAMBDA_ATTRIBUTES +# endif + // Clang modules take a significant compile time hit when pushing and popping diagnostics. // Since all the headers are marked as system headers in the modulemap, we can simply disable this // pushing and popping when building with clang modules. @@ -567,6 +574,7 @@ typedef __char32_t char32_t; _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++17-extensions") \ _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++20-extensions") \ _LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION \ + _LIBCPP_CLANG_DIANGOSTIC_INGORED_CXX23_LAMBDA_ATTRIBUTES \ _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++14-extensions") \ _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++17-extensions") \ _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++20-extensions") \ diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h index 5feaf7e5a064ad..fd71f53b51c1e6 100644 --- a/libcxx/include/__format/format_functions.h +++ b/libcxx/include/__format/format_functions.h @@ -11,6 +11,8 @@ #define _LIBCPP___FORMAT_FORMAT_FUNCTIONS #include <__algorithm/clamp.h> +#include <__algorithm/ranges_find_first_of.h> +#include <__chrono/statically_widen.h> #include <__concepts/convertible_to.h> #include <__concepts/same_as.h> #include <__config> @@ -447,10 +449,46 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) { } # endif +// Try constant folding the format string instead of going through the whole formatting machinery. If there is no +// constant folding no extra code should be emitted (with optimizations enabled) and the function returns nullopt. When +// constant folding is successful, the formatting is performed and the resulting string is returned. +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional> __try_constant_folding_format( + basic_string_view<_CharT> __fmt, + basic_format_args>, _CharT>> __args) { + + // Fold strings not containing '{' or '}' to just return the string + if (bool __is_identity = [&] [[__gnu__::__pure__]] // Make sure the compiler knows this call can be eliminated + { return std::ranges::find_first_of(__fmt, array{'{', '}'}) == __fmt.end(); }(); + __builtin_constant_p(__is_identity) && __is_identity) + return basic_string<_CharT>{__fmt}; + + // Fold '{}' to the appropriate conversion function + if (auto __only_first_arg = __fmt == _LIBCPP_STATICALLY_WIDEN(_CharT, "{}"); + __builtin_constant_p(__only_first_arg) && __only_first_arg) { + if (auto __arg = __args.get(0); __builtin_constant_p(__arg.__type_)) { + return std::__visit_format_arg( + [](_Tp&& __argument) -> optional> { + if constexpr (is_same_v, basic_string_view<_CharT>>) { + return basic_string<_CharT>{__argument}; + } else { + return nullopt; + } + }, + __arg); + } + } + + return nullopt; +} + // TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup // fires too eagerly, see http://llvm.org/PR61563. template [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string vformat(string_view __fmt, format_args __args) { + auto __result = std::__try_constant_folding_format(__fmt, __args); + if (__result.has_value()) + return *__result; __format::__allocating_buffer __buffer; std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args); return string{__buffer.__view()}; @@ -462,6 +500,9 @@ template template [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring vformat(wstring_view __fmt, wformat_args __args) { + auto __result = std::__try_constant_folding_format(__fmt, __args); + if (__result.has_value()) + return *__result; __format::__allocating_buffer __buffer; std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args); return wstring{__buffer.__view()}; diff --git a/libcxx/test/benchmarks/format/format.bench.cpp b/libcxx/test/benchmarks/format/format.bench.cpp index 267ef229506685..044cad6d09e40d 100644 --- a/libcxx/test/benchmarks/format/format.bench.cpp +++ b/libcxx/test/benchmarks/format/format.bench.cpp @@ -35,4 +35,13 @@ BENCHMARK(BM_format_string)->RangeMultiplier(2)->Range(1, 1 << 20); BENCHMARK(BM_format_string)->RangeMultiplier(2)->Range(1, 1 << 20); #endif +template +static void BM_string_without_formatting(benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize(std::format(CSTR("Hello, World!"))); + } +} +BENCHMARK(BM_string_without_formatting); +BENCHMARK(BM_string_without_formatting); + BENCHMARK_MAIN(); From libcxx-commits at lists.llvm.org Mon Feb 3 11:28:14 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Mon, 03 Feb 2025 11:28:14 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <67a118ce.170a0220.76a53.26b6@mx.google.com> github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning:
You can test this locally with the following command: ``````````bash git-clang-format --diff 956cfa69b153a0e798060f67e713790eeefebc04 0db3132b818ba1fd1f8d5b5d684e5170d31375df --extensions ,h,cpp -- libcxx/include/__config libcxx/include/__format/format_functions.h libcxx/test/benchmarks/format/format.bench.cpp ``````````
View the diff from clang-format here. ``````````diff diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h index fd71f53b51..43d1a6ce1f 100644 --- a/libcxx/include/__format/format_functions.h +++ b/libcxx/include/__format/format_functions.h @@ -456,7 +456,6 @@ template [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional> __try_constant_folding_format( basic_string_view<_CharT> __fmt, basic_format_args>, _CharT>> __args) { - // Fold strings not containing '{' or '}' to just return the string if (bool __is_identity = [&] [[__gnu__::__pure__]] // Make sure the compiler knows this call can be eliminated { return std::ranges::find_first_of(__fmt, array{'{', '}'}) == __fmt.end(); }(); ``````````
https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Mon Feb 3 11:41:12 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 11:41:12 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) In-Reply-To: Message-ID: <67a11bd8.a70a0220.1bbe26.21b0@mx.google.com> https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/125550 >From 198180b2791c4e64886ff9bd81fb2d31ef45f23a Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sat, 25 Jan 2025 20:27:14 +0100 Subject: [PATCH 1/2] [libc++][chrono] implements TAI clock. Implements parts of: - P0355 Extending to Calendars and Time Zones - P1361 Integration of chrono with text formatting - LWG3359 leap second support should allow for negative leap seconds --- libcxx/docs/Status/FormatPaper.csv | 2 +- libcxx/include/CMakeLists.txt | 1 + libcxx/include/__chrono/convert_to_tm.h | 13 + libcxx/include/__chrono/formatter.h | 14 + libcxx/include/__chrono/ostream.h | 7 + libcxx/include/__chrono/tai_clock.h | 98 ++ libcxx/include/chrono | 31 + libcxx/include/module.modulemap | 4 + libcxx/modules/std/chrono.inc | 2 +- .../diagnostics/chrono.nodiscard.verify.cpp | 11 + .../time.clock.tai/tai_time.ostream.pass.cpp | 164 +++ .../time.clock.tai.members/from_utc.pass.cpp | 159 +++ .../time.clock.tai.members/now.pass.cpp | 30 + .../time.clock.tai.members/to_utc.pass.cpp | 161 +++ .../time.clock.tai/types.compile.pass.cpp | 59 ++ .../time/time.syn/formatter.tai_time.pass.cpp | 998 ++++++++++++++++++ libcxx/test/support/concat_macros.h | 5 + 17 files changed, 1757 insertions(+), 2 deletions(-) create mode 100644 libcxx/include/__chrono/tai_clock.h create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp create mode 100644 libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp diff --git a/libcxx/docs/Status/FormatPaper.csv b/libcxx/docs/Status/FormatPaper.csv index 343fa62f135654..de64e9c25a7771 100644 --- a/libcxx/docs/Status/FormatPaper.csv +++ b/libcxx/docs/Status/FormatPaper.csv @@ -3,7 +3,7 @@ Section,Description,Dependencies,Assignee,Status,First released version `[time.syn] `_,"Formatter ``chrono::duration``",,Mark de Wever,|Complete|,16 `[time.syn] `_,"Formatter ``chrono::sys_time``",,Mark de Wever,|Complete|,17 `[time.syn] `_,"Formatter ``chrono::utc_time``",A ```` implementation,Mark de Wever,|Complete|,20 -`[time.syn] `_,"Formatter ``chrono::tai_time``",A ```` implementation,Mark de Wever,,, ++`[time.syn] `_,"Formatter ``chrono::tai_time``",,Mark de Wever,|Complete|,21 `[time.syn] `_,"Formatter ``chrono::gps_time``",A ```` implementation,Mark de Wever,,, `[time.syn] `_,"Formatter ``chrono::file_time``",,Mark de Wever,|Complete|,17 `[time.syn] `_,"Formatter ``chrono::local_time``",,Mark de Wever,|Complete|,17 diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8dac823503d73f..ce805b4eb7b8b4 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -270,6 +270,7 @@ set(files __chrono/steady_clock.h __chrono/sys_info.h __chrono/system_clock.h + __chrono/tai_clock.h __chrono/time_point.h __chrono/time_zone.h __chrono/time_zone_link.h diff --git a/libcxx/include/__chrono/convert_to_tm.h b/libcxx/include/__chrono/convert_to_tm.h index 7d06a38d87f26d..934293ce382345 100644 --- a/libcxx/include/__chrono/convert_to_tm.h +++ b/libcxx/include/__chrono/convert_to_tm.h @@ -23,6 +23,7 @@ #include <__chrono/statically_widen.h> #include <__chrono/sys_info.h> #include <__chrono/system_clock.h> +#include <__chrono/tai_clock.h> #include <__chrono/time_point.h> #include <__chrono/utc_clock.h> #include <__chrono/weekday.h> @@ -112,6 +113,16 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::utc_time<_Duration> __tp) { return __result; } +template +_LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::tai_time<_Duration> __tp) { + using _Rp = common_type_t<_Duration, chrono::seconds>; + // The time between the TAI epoch (1958-01-01) and UNIX epoch (1970-01-01). + // This avoids leap second conversion when going from TAI to UTC. + // (It also avoids issues when the date is before the UTC epoch.) + constexpr chrono::seconds __offset{4383 * 24 * 60 * 60}; + return std::__convert_to_tm<_Tm>(chrono::sys_time<_Rp>{__tp.time_since_epoch() - __offset}); +} + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION @@ -131,6 +142,8 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) { # if _LIBCPP_HAS_EXPERIMENTAL_TZDB else if constexpr (same_as) return std::__convert_to_tm<_Tm>(__value); + else if constexpr (same_as) + return std::__convert_to_tm<_Tm>(__value); # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION else if constexpr (same_as) diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h index d17acd274e4cda..753a824a3c50d7 100644 --- a/libcxx/include/__chrono/formatter.h +++ b/libcxx/include/__chrono/formatter.h @@ -31,6 +31,7 @@ # include <__chrono/statically_widen.h> # include <__chrono/sys_info.h> # include <__chrono/system_clock.h> +# include <__chrono/tai_clock.h> # include <__chrono/time_point.h> # include <__chrono/utc_clock.h> # include <__chrono/weekday.h> @@ -231,6 +232,8 @@ _LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const # if _LIBCPP_HAS_EXPERIMENTAL_TZDB if constexpr (same_as<_Tp, chrono::sys_info>) return {__value.abbrev, __value.offset}; + else if constexpr (__is_time_point<_Tp> && requires { requires same_as; }) + return {"TAI", chrono::seconds{0}}; # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) return __formatter::__convert_to_time_zone(__value.get_info()); @@ -734,6 +737,17 @@ struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : pub } }; +template +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : public __formatter_chrono<_CharT> { +public: + using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); + } +}; + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM diff --git a/libcxx/include/__chrono/ostream.h b/libcxx/include/__chrono/ostream.h index ed9ad8e346ba94..b8cd6a4680662b 100644 --- a/libcxx/include/__chrono/ostream.h +++ b/libcxx/include/__chrono/ostream.h @@ -26,6 +26,7 @@ # include <__chrono/statically_widen.h> # include <__chrono/sys_info.h> # include <__chrono/system_clock.h> +# include <__chrono/tai_clock.h> # include <__chrono/utc_clock.h> # include <__chrono/weekday.h> # include <__chrono/year.h> @@ -71,6 +72,12 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const utc_time<_Duration>& __tp return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); } +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const tai_time<_Duration>& __tp) { + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); +} + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM diff --git a/libcxx/include/__chrono/tai_clock.h b/libcxx/include/__chrono/tai_clock.h new file mode 100644 index 00000000000000..18ba329b7b8fb4 --- /dev/null +++ b/libcxx/include/__chrono/tai_clock.h @@ -0,0 +1,98 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_TAI_CLOCK_H +#define _LIBCPP___CHRONO_TAI_CLOCK_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if _LIBCPP_HAS_EXPERIMENTAL_TZDB + +# include <__chrono/duration.h> +# include <__chrono/time_point.h> +# include <__chrono/utc_clock.h> +# include <__config> +# include <__type_traits/common_type.h> + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION + +namespace chrono { + +class tai_clock; + +template +using tai_time = time_point; +using tai_seconds = tai_time; + +// [time.clock.tai.overview]/1 +// The clock tai_clock measures seconds since 1958-01-01 00:00:00 and is +// offset 10s ahead of UTC at this date. That is, 1958-01-01 00:00:00 TAI is +// equivalent to 1957-12-31 23:59:50 UTC. Leap seconds are not inserted into +// TAI. Therefore every time a leap second is inserted into UTC, UTC shifts +// another second with respect to TAI. For example by 2000-01-01 there had +// been 22 positive and 0 negative leap seconds inserted so 2000-01-01 +// 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI (22s plus the +// initial 10s offset). +// +// Note this does not specify what the UTC offset before 1958-01-01 00:00:00 +// TAI is. However the member functions are fully specified in the standard. +// https://koka-lang.github.io/koka/doc/std_time_utc.html contains more +// information and references. +class tai_clock { +public: + using rep = utc_clock::rep; + using period = utc_clock::period; + using duration = chrono::duration; + using time_point = chrono::time_point; + static constexpr bool is_steady = false; // The utc_clock is not steady. + + // The static difference between UTC and TAI time. + static constexpr chrono::seconds __offset{378691210}; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static time_point now() { return from_utc(utc_clock::now()); } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static utc_time> + to_utc(const tai_time<_Duration>& __time) noexcept { + using _Rp = common_type_t<_Duration, seconds>; + _Duration __time_since_epoch = __time.time_since_epoch(); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch >= utc_time<_Rp>::min().time_since_epoch() + __offset, + "the TAI to UTC conversion would underflow"); + + return utc_time<_Rp>{__time_since_epoch - __offset}; + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static tai_time> + from_utc(const utc_time<_Duration>& __time) noexcept { + using _Rp = common_type_t<_Duration, seconds>; + _Duration __time_since_epoch = __time.time_since_epoch(); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch <= utc_time<_Rp>::max().time_since_epoch() - __offset, + "the UTC to TAI conversion would overflow"); + + return tai_time<_Rp>{__time_since_epoch + __offset}; + } +}; + +} // namespace chrono + +# endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && + // _LIBCPP_HAS_LOCALIZATION + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB + +#endif // _LIBCPP___CHRONO_TAI_CLOCK_H diff --git a/libcxx/include/chrono b/libcxx/include/chrono index 10695eea649fb7..bd4c98600440c4 100644 --- a/libcxx/include/chrono +++ b/libcxx/include/chrono @@ -335,6 +335,34 @@ struct leap_second_info { // C++20 template // C++20 leap_second_info get_leap_second_info(const utc_time& ut); + +// [time.clock.tai], class tai_clock +class tai_clock { // C++20 +public: + using rep = a signed arithmetic type; + using period = ratio; + using duration = chrono::duration; + using time_point = chrono::time_point; + static constexpr bool is_steady = unspecified; + + static time_point now(); + + template + static utc_time> + to_utc(const tai_time& t); + template + static tai_time> + from_utc(const utc_time& t); +}; + +template +using tai_time = time_point; // C++20 +using tai_seconds = tai_time; // C++20 + +template // C++20 + basic_ostream& + operator<<(basic_ostream& os, const tai_time& t); + class file_clock // C++20 { public: @@ -898,6 +926,8 @@ namespace std { struct formatter, charT>; // C++20 template struct formatter, charT>; // C++20 + template + struct formatter, charT>; // C++20 template struct formatter, charT>; // C++20 template @@ -1014,6 +1044,7 @@ constexpr chrono::year operator ""y(unsigned lo # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION # include <__chrono/leap_second.h> +# include <__chrono/tai_clock.h> # include <__chrono/time_zone.h> # include <__chrono/time_zone_link.h> # include <__chrono/tzdb.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4bae02137b37b2..fd39c946b992a4 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -967,6 +967,10 @@ module std [system] { header "__chrono/system_clock.h" export std.chrono.time_point } + module tai_clock { + header "__chrono/tai_clock.h" + export std.chrono.time_point + } module time_point { header "__chrono/time_point.h" } module time_zone_link { header "__chrono/time_zone_link.h" } module time_zone { header "__chrono/time_zone.h" } diff --git a/libcxx/modules/std/chrono.inc b/libcxx/modules/std/chrono.inc index 98f14f716c2078..43e8da36e90448 100644 --- a/libcxx/modules/std/chrono.inc +++ b/libcxx/modules/std/chrono.inc @@ -97,13 +97,13 @@ export namespace std { using std::chrono::get_leap_second_info; -# if 0 // [time.clock.tai], class tai_clock using std::chrono::tai_clock; using std::chrono::tai_seconds; using std::chrono::tai_time; +# if 0 // [time.clock.gps], class gps_clock using std::chrono::gps_clock; diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp index 644c5b598c018d..bb40e0cfc4e1b8 100644 --- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp +++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp @@ -102,4 +102,15 @@ void test(std::chrono::time_zone tz, std::chrono::time_zone_link link, std::chro zt.get_sys_time(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} zt.get_info(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} } + + { // [time.clock.tai] + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::now(); + + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::to_utc(std::chrono::tai_seconds{}); + + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::from_utc(std::chrono::utc_seconds{}); + } } diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp new file mode 100644 index 00000000000000..3508ceb8b2d3f6 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp @@ -0,0 +1,164 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb +// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME + +// TODO FMT This test should not require std::to_chars(floating-point) +// XFAIL: availability-fp_to_chars-missing + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// REQUIRES: locale.fr_FR.UTF-8 +// REQUIRES: locale.ja_JP.UTF-8 + +// + +// class taitem_clock; + +// template +// basic_ostream& +// operator<<(basic_ostream& os, const tai_time& tp); + +#include +#include +#include +#include + +#include "make_string.h" +#include "platform_support.h" // locale name macros +#include "test_macros.h" + +#define SV(S) MAKE_STRING_VIEW(CharT, S) + +template +static std::basic_string stream_c_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static std::basic_string stream_fr_FR_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + const std::locale locale(LOCALE_fr_FR_UTF_8); + sstr.imbue(locale); + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static std::basic_string stream_ja_JP_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + const std::locale locale(LOCALE_ja_JP_UTF_8); + sstr.imbue(locale); + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static void test_c() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + assert(stream_c_locale(cr::tai_time{946'688'523'123'456'789ns}) == + SV("1988-01-01 01:02:03.123456789")); + assert(stream_c_locale(cr::tai_time{946'688'523'123'456us}) == + SV("1988-01-01 01:02:03.123456")); + + assert(stream_c_locale(cr::tai_time{946'684'822'123ms}) == SV("1988-01-01 00:00:22.123")); + assert(stream_c_locale(cr::tai_seconds{1'234'567'890s}) == SV("1997-02-13 23:31:30")); + assert(stream_c_locale(cr::tai_time{20'576'131min}) == SV("1997-02-13 23:31:00")); + assert(stream_c_locale(cr::tai_time{342'935h}) == SV("1997-02-13 23:00:00")); + + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{60}}) == SV("1958-01-01 00:02:00")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:30:00.0")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:15:00.00")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{36611}}) == SV("1958-01-01 01:01:01.1")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{12'345'678'9010}}) == SV("1997-02-13 23:31:30.10")); +} + +template +static void test_fr_FR() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + assert(stream_fr_FR_locale(cr::tai_time{946'688'523'123'456'789ns}) == + SV("1988-01-01 01:02:03,123456789")); + assert(stream_fr_FR_locale(cr::tai_time{946'688'523'123'456us}) == + SV("1988-01-01 01:02:03,123456")); + + assert(stream_fr_FR_locale(cr::tai_time{946'684'822'123ms}) == + SV("1988-01-01 00:00:22,123")); + assert(stream_fr_FR_locale(cr::tai_seconds{1'234'567'890s}) == SV("1997-02-13 23:31:30")); + assert(stream_fr_FR_locale(cr::tai_time{20'576'131min}) == SV("1997-02-13 23:31:00")); + assert(stream_fr_FR_locale(cr::tai_time{342'935h}) == SV("1997-02-13 23:00:00")); + + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{60}}) == SV("1958-01-01 00:02:00")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:30:00,0")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:15:00,00")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{36611}}) == SV("1958-01-01 01:01:01,1")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{12'345'678'9010}}) == SV("1997-02-13 23:31:30,10")); +} + +template +static void test_ja_JP() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + assert(stream_ja_JP_locale(cr::tai_time{946'688'523'123'456'789ns}) == + SV("1988-01-01 01:02:03.123456789")); + assert(stream_ja_JP_locale(cr::tai_time{946'688'523'123'456us}) == + SV("1988-01-01 01:02:03.123456")); + + assert(stream_ja_JP_locale(cr::tai_time{946'684'822'123ms}) == + SV("1988-01-01 00:00:22.123")); + assert(stream_ja_JP_locale(cr::tai_seconds{1'234'567'890s}) == SV("1997-02-13 23:31:30")); + assert(stream_ja_JP_locale(cr::tai_time{20'576'131min}) == SV("1997-02-13 23:31:00")); + assert(stream_ja_JP_locale(cr::tai_time{342'935h}) == SV("1997-02-13 23:00:00")); + + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{60}}) == SV("1958-01-01 00:02:00")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:30:00.0")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:15:00.00")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{36611}}) == SV("1958-01-01 01:01:01.1")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{12'345'678'9010}}) == SV("1997-02-13 23:31:30.10")); +} + +template +static void test() { + test_c(); + test_fr_FR(); + test_ja_JP(); +} + +int main(int, char**) { + test(); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + + return 0; +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp new file mode 100644 index 00000000000000..b3ba97bdc49dd9 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp @@ -0,0 +1,159 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// +// +// class tai_clock; + +// static tai_time> +// from_utc(const utc<_Duration>& __time) noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "assert_macros.h" +#include "concat_macros.h" + +static void test_known_values() { + namespace cr = std::chrono; + using namespace std::literals::chrono_literals; + constexpr auto unix_to_tai_epoch_offset = cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + + // [time.clock.tai.overview]/1 + // ... 1958-01-01 00:00:00 TAI is equivalent to 1957-12-31 23:59:50 UTC + // ... 2000-01-01 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI + + assert(cr::tai_clock::from_utc(cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 1958} - 10s)) == + cr::tai_seconds{0s}); + + assert(cr::tai_clock::from_utc(cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 2000})) == + cr::tai_seconds{(cr::sys_days{cr::January / 1 / 2000} + unix_to_tai_epoch_offset).time_since_epoch()} + 32s); +} + +template +static void test_leap_seconds(std::chrono::utc_time utc, + std::chrono::tai_time expected, + std::source_location loc = std::source_location::current()) { + auto tai = std::chrono::tai_clock::from_utc(utc); + TEST_REQUIRE(tai == expected, + TEST_WRITE_CONCATENATED(loc, "\nExpected output ", expected, "\nActual output ", tai, '\n')); +} + +// Tests set if existing database entries at the time of writing. +static void test_transitions() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + // "sys" is the time of the transition to the next leap second. + // "elapsed" is the number of leap seconds before the transition. + auto test_transition = [](cr::sys_days sys, cr::seconds elapsed) { + constexpr auto unix_to_tai_epoch_offset = + cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + cr::tai_seconds tai{sys.time_since_epoch() + unix_to_tai_epoch_offset + elapsed}; + + test_leap_seconds(cr::utc_clock::from_sys(sys - 1ns), tai - 1ns); + test_leap_seconds(cr::utc_clock::from_sys(sys), tai + 1s); + test_leap_seconds(cr::utc_clock::from_sys(sys) + 1ns, tai + 1s + 1ns); + }; + + // Transitions from the start of UTC. + test_transition(cr::sys_days{cr::July / 1 / 1972}, 10s); + test_transition(cr::sys_days{cr::January / 1 / 1973}, 11s); + test_transition(cr::sys_days{cr::January / 1 / 1974}, 12s); + test_transition(cr::sys_days{cr::January / 1 / 1975}, 13s); + test_transition(cr::sys_days{cr::January / 1 / 1976}, 14s); + test_transition(cr::sys_days{cr::January / 1 / 1977}, 15s); + test_transition(cr::sys_days{cr::January / 1 / 1978}, 16s); + test_transition(cr::sys_days{cr::January / 1 / 1979}, 17s); + test_transition(cr::sys_days{cr::January / 1 / 1980}, 18s); + test_transition(cr::sys_days{cr::July / 1 / 1981}, 19s); + test_transition(cr::sys_days{cr::July / 1 / 1982}, 20s); + test_transition(cr::sys_days{cr::July / 1 / 1983}, 21s); + test_transition(cr::sys_days{cr::July / 1 / 1985}, 22s); + test_transition(cr::sys_days{cr::January / 1 / 1988}, 23s); + test_transition(cr::sys_days{cr::January / 1 / 1990}, 24s); + test_transition(cr::sys_days{cr::January / 1 / 1991}, 25s); + test_transition(cr::sys_days{cr::July / 1 / 1992}, 26s); + test_transition(cr::sys_days{cr::July / 1 / 1993}, 27s); + test_transition(cr::sys_days{cr::July / 1 / 1994}, 28s); + test_transition(cr::sys_days{cr::January / 1 / 1996}, 29s); + test_transition(cr::sys_days{cr::July / 1 / 1997}, 30s); + test_transition(cr::sys_days{cr::January / 1 / 1999}, 31s); + test_transition(cr::sys_days{cr::January / 1 / 2006}, 32s); + test_transition(cr::sys_days{cr::January / 1 / 2009}, 33s); + test_transition(cr::sys_days{cr::July / 1 / 2012}, 34s); + test_transition(cr::sys_days{cr::July / 1 / 2015}, 35s); + test_transition(cr::sys_days{cr::January / 1 / 2017}, 36s); +} + +// Tests whether the return type is the expected type. +static void test_return_type() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0ns}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0us}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0ms}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::seconds{0}}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::minutes{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::hours{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::days{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::weeks{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::months{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::years{0}}); + } +} + +int main(int, const char**) { + using namespace std::literals::chrono_literals; + std::chrono::utc_seconds time = std::chrono::utc_seconds{0s}; + static_assert(noexcept(std::chrono::tai_clock::from_utc(time))); + + test_known_values(); + test_transitions(); + test_return_type(); +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp new file mode 100644 index 00000000000000..c96ace82daca16 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// +// +// class tai; + +// static time_point now(); + +#include +#include + +int main(int, const char**) { + using clock = std::chrono::tai_clock; + std::same_as decltype(auto) t = clock::now(); + + assert(t >= clock::time_point::min()); + assert(t <= clock::time_point::max()); +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp new file mode 100644 index 00000000000000..210f5b8a125b33 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp @@ -0,0 +1,161 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// +// +// class tai_clock; + +// static utc_time> +// to_utc(const tai_time<_Duration>& __time) noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "assert_macros.h" +#include "concat_macros.h" + +static void test_known_values() { + namespace cr = std::chrono; + using namespace std::literals::chrono_literals; + constexpr auto unix_to_tai_epoch_offset = cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + + // [time.clock.tai.overview]/1 + // ... 1958-01-01 00:00:00 TAI is equivalent to 1957-12-31 23:59:50 UTC + // ... 2000-01-01 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI + + assert(cr::tai_clock::to_utc(cr::tai_seconds{0s}) == + cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 1958} - 10s)); + + assert(cr::tai_clock::to_utc( + cr::tai_seconds{(cr::sys_days{cr::January / 1 / 2000} + unix_to_tai_epoch_offset).time_since_epoch()} + + 32s) == cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 2000})); +} + +template +static void test_leap_seconds(std::chrono::tai_time tai, + std::chrono::utc_time expected, + std::source_location loc = std::source_location::current()) { + auto utc = std::chrono::tai_clock::to_utc(tai); + TEST_REQUIRE(utc == expected, + TEST_WRITE_CONCATENATED(loc, "\nExpected output ", expected, "\nActual output ", utc, '\n')); +} + +// Tests set if existing database entries at the time of writing. +static void test_transitions() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + // "sys" is the time of the transition to the next leap second. + // "elapsed" is the number of leap seconds before the transition. + auto test_transition = [](cr::sys_days sys, cr::seconds elapsed) { + constexpr auto unix_to_tai_epoch_offset = + cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + cr::tai_seconds tai{sys.time_since_epoch() + unix_to_tai_epoch_offset + elapsed}; + + test_leap_seconds(tai - 1ns, cr::utc_clock::from_sys(sys - 1ns)); + test_leap_seconds(tai + 1s, cr::utc_clock::from_sys(sys)); + test_leap_seconds(tai + 1s + 1ns, cr::utc_clock::from_sys(sys + 1ns)); + }; + + // Transitions from the start of UTC. + test_transition(cr::sys_days{cr::July / 1 / 1972}, 10s); + test_transition(cr::sys_days{cr::January / 1 / 1973}, 11s); + test_transition(cr::sys_days{cr::January / 1 / 1974}, 12s); + test_transition(cr::sys_days{cr::January / 1 / 1975}, 13s); + test_transition(cr::sys_days{cr::January / 1 / 1976}, 14s); + test_transition(cr::sys_days{cr::January / 1 / 1977}, 15s); + test_transition(cr::sys_days{cr::January / 1 / 1978}, 16s); + test_transition(cr::sys_days{cr::January / 1 / 1979}, 17s); + test_transition(cr::sys_days{cr::January / 1 / 1980}, 18s); + test_transition(cr::sys_days{cr::July / 1 / 1981}, 19s); + test_transition(cr::sys_days{cr::July / 1 / 1982}, 20s); + test_transition(cr::sys_days{cr::July / 1 / 1983}, 21s); + test_transition(cr::sys_days{cr::July / 1 / 1985}, 22s); + test_transition(cr::sys_days{cr::January / 1 / 1988}, 23s); + test_transition(cr::sys_days{cr::January / 1 / 1990}, 24s); + test_transition(cr::sys_days{cr::January / 1 / 1991}, 25s); + test_transition(cr::sys_days{cr::July / 1 / 1992}, 26s); + test_transition(cr::sys_days{cr::July / 1 / 1993}, 27s); + test_transition(cr::sys_days{cr::July / 1 / 1994}, 28s); + test_transition(cr::sys_days{cr::January / 1 / 1996}, 29s); + test_transition(cr::sys_days{cr::July / 1 / 1997}, 30s); + test_transition(cr::sys_days{cr::January / 1 / 1999}, 31s); + test_transition(cr::sys_days{cr::January / 1 / 2006}, 32s); + test_transition(cr::sys_days{cr::January / 1 / 2009}, 33s); + test_transition(cr::sys_days{cr::July / 1 / 2012}, 34s); + test_transition(cr::sys_days{cr::July / 1 / 2015}, 35s); + test_transition(cr::sys_days{cr::January / 1 / 2017}, 36s); +} + +// Tests whether the return type is the expected type. +static void test_return_type() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{0ns}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{0us}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{0ms}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::seconds{0}}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::minutes{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::hours{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::days{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::weeks{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::months{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::years{0}}); + } +} + +int main(int, const char**) { + using namespace std::literals::chrono_literals; + + std::chrono::tai_seconds time = std::chrono::tai_seconds{0s}; + static_assert(noexcept(std::chrono::tai_clock::to_utc(time))); + + test_known_values(); + test_transitions(); + test_return_type(); +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp new file mode 100644 index 00000000000000..c4af65d447c357 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// + +// class tai_clock { +// public: +// using rep = a signed arithmetic type; +// using period = ratio; +// using duration = chrono::duration; +// using time_point = chrono::time_point; +// static constexpr bool is_steady = unspecified; +// +// ... +// }; +// +// template +// using tai_time = time_point; +// using tai_seconds = tai_time; + +#include +#include + +#include "test_macros.h" + +// class tai_clock +using rep = std::chrono::tai_clock::rep; +using period = std::chrono::tai_clock::period; +using duration = std::chrono::tai_clock::duration; +using time_point = std::chrono::tai_clock::time_point; +constexpr bool is_steady = std::chrono::tai_clock::is_steady; + +// Tests the values. part of them are implementation defined. +LIBCPP_STATIC_ASSERT(std::same_as); +static_assert(std::is_arithmetic_v); +static_assert(std::is_signed_v); + +LIBCPP_STATIC_ASSERT(std::same_as); +static_assert(std::same_as>); + +static_assert(std::same_as>); +static_assert(std::same_as>); +LIBCPP_STATIC_ASSERT(is_steady == false); + +// typedefs +static_assert(std::same_as, std::chrono::time_point>); +static_assert(std::same_as, std::chrono::time_point>); +static_assert(std::same_as>); diff --git a/libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp b/libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp new file mode 100644 index 00000000000000..7ca088cc6e8f46 --- /dev/null +++ b/libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp @@ -0,0 +1,998 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb +// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME + +// TODO FMT This test should not require std::to_chars(floating-point) +// XFAIL: availability-fp_to_chars-missing + +// XFAIL: libcpp-has-no-experimental-tzdb +// XFAIL: availability-tzdb-missing + +// REQUIRES: locale.fr_FR.UTF-8 +// REQUIRES: locale.ja_JP.UTF-8 + +// + +// template +// struct formatter, charT>; + +#include +#include + +#include +#include +#include +#include +#include + +#include "formatter_tests.h" +#include "make_string.h" +#include "platform_support.h" // locale name macros +#include "test_macros.h" + +template +static void test_no_chrono_specs() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output + + // [time.syn] + // using nanoseconds = duration; + // using microseconds = duration; + // using milliseconds = duration; + // using seconds = duration; + // using minutes = duration>; + // using hours = duration>; + check(SV("1413-08-04 22:06:56"), SV("{}"), cr::tai_seconds(-17'179'869'184s)); // Minimum value for 35 bits. + check(SV("1889-12-12 20:45:52"), SV("{}"), cr::tai_seconds(-2'147'483'648s)); + + check(SV("1957-12-31 00:00:00"), SV("{}"), cr::tai_seconds(-24h)); + check(SV("1957-12-31 06:00:00"), SV("{}"), cr::tai_seconds(-18h)); + check(SV("1957-12-31 12:00:00"), SV("{}"), cr::tai_seconds(-12h)); + check(SV("1957-12-31 18:00:00"), SV("{}"), cr::tai_seconds(-6h)); + check(SV("1957-12-31 23:59:59"), SV("{}"), cr::tai_seconds(-1s)); + + check(SV("1958-01-01 00:00:00"), SV("{}"), cr::tai_seconds(0s)); + check(SV("1988-01-01 00:00:00"), SV("{}"), cr::tai_seconds(946'684'800s)); + check(SV("1988-01-01 01:02:03"), SV("{}"), cr::tai_seconds(946'688'523s)); + + check(SV("2026-01-19 03:14:07"), SV("{}"), cr::tai_seconds(2'147'483'647s)); + check(SV("2502-05-30 01:53:03"), SV("{}"), cr::tai_seconds(17'179'869'183s)); // Maximum value for 35 bits. + + check(SV("1988-01-01 01:02:03.123"), SV("{}"), cr::tai_time(946'688'523'123ms)); + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_year() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = + SV("{:%%C='%C'%t%%EC='%EC'%t%%y='%y'%t%%Oy='%Oy'%t%%Ey='%Ey'%t%%Y='%Y'%t%%EY='%EY'%n}"); + constexpr std::basic_string_view lfmt = + SV("{:L%%C='%C'%t%%EC='%EC'%t%%y='%y'%t%%Oy='%Oy'%t%%Ey='%Ey'%t%%Y='%Y'%t%%EY='%EY'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%C='19'\t%EC='19'\t%y='58'\t%Oy='58'\t%Ey='58'\t%Y='1958'\t%EY='1958'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%C='20'\t%EC='20'\t%y='09'\t%Oy='09'\t%Ey='09'\t%Y='2009'\t%EY='2009'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%C='19'\t%EC='19'\t%y='58'\t%Oy='58'\t%Ey='58'\t%Y='1958'\t%EY='1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%C='20'\t%EC='20'\t%y='09'\t%Oy='09'\t%Ey='09'\t%Y='2009'\t%EY='2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%C='19'\t%EC='19'\t%y='58'\t%Oy='58'\t%Ey='58'\t%Y='1958'\t%EY='1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%C='20'\t%EC='20'\t%y='09'\t%Oy='09'\t%Ey='09'\t%Y='2009'\t%EY='2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX)||defined(__FreeBSD__) + check(loc, + SV("%C='19'\t%EC='昭和'\t%y='58'\t%Oy='五十八'\t%Ey='33'\t%Y='1958'\t%EY='昭和33年'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%C='20'\t%EC='平成'\t%y='09'\t%Oy='九'\t%Ey='21'\t%Y='2009'\t%EY='平成21年'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX)||defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_month() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%b='%b'%t%%h='%h'%t%%B='%B'%t%%m='%m'%t%%Om='%Om'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%b='%b'%t%%h='%h'%t%%B='%B'%t%%m='%m'%t%%Om='%Om'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%b='Jan'\t%h='Jan'\t%B='January'\t%m='01'\t%Om='01'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%b='May'\t%h='May'\t%B='May'\t%m='05'\t%Om='05'\n"), + fmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI on Wednesday, 18 May 2033 + + // Use the global locale (fr_FR) +#if defined(__APPLE__) + check(SV("%b='jan'\t%h='jan'\t%B='janvier'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 +#else + check(SV("%b='janv.'\t%h='janv.'\t%B='janvier'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 +#endif + + check(SV("%b='mai'\t%h='mai'\t%B='mai'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI on Wednesday, 18 May 2033 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#ifdef _WIN32 + check(loc, + SV("%b='1'\t%h='1'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b='5'\t%h='5'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#elif defined(_AIX) // _WIN32 + check(loc, + SV("%b='1月'\t%h='1月'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b='5月'\t%h='5月'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#elif defined(__APPLE__) // _WIN32 + check(loc, + SV("%b=' 1'\t%h=' 1'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b=' 5'\t%h=' 5'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#elif defined(__FreeBSD__) // _WIN32 + check(loc, + SV("%b=' 1月'\t%h=' 1月'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b=' 5月'\t%h=' 5月'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#else // _WIN32 + check(loc, + SV("%b=' 1月'\t%h=' 1月'\t%B='1月'\t%m='01'\t%Om='一'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b=' 5月'\t%h=' 5月'\t%B='5月'\t%m='05'\t%Om='五'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#endif // _WIN32 + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_day() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%d='%d'%t%%Od='%Od'%t%%e='%e'%t%%Oe='%Oe'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%d='%d'%t%%Od='%Od'%t%%e='%e'%t%%Oe='%Oe'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%d='13'\t%Od='13'\t%e='13'\t%Oe='13'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%d='13'\t%Od='13'\t%e='13'\t%Oe='13'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%d='13'\t%Od='13'\t%e='13'\t%Oe='13'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%d='01'\t%Od='一'\t%e=' 1'\t%Oe='一'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%d='13'\t%Od='十三'\t%e='13'\t%Oe='十三'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_weekday() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = + SV("{:%%a='%a'%t%%A='%A'%t%%u='%u'%t%%Ou='%Ou'%t%%w='%w'%t%%Ow='%Ow'%n}"); + constexpr std::basic_string_view lfmt = + SV("{:L%%a='%a'%t%%A='%A'%t%%u='%u'%t%%Ou='%Ou'%t%%w='%w'%t%%Ow='%Ow'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%a='Wed'\t%A='Wednesday'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%a='Sun'\t%A='Sunday'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + fmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 + + // Use the global locale (fr_FR) +#if defined(__APPLE__) + check(SV("%a='mer'\t%A='Mercredi'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%a='Dim'\t%A='Dimanche'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#else + check(SV("%a='mer.'\t%A='mercredi'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%a='dim.'\t%A='dimanche'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#endif + + // Use supplied locale (ja_JP). + // This locale has a different alternate, but not on all platforms +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%a='水'\t%A='水曜日'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%a='日'\t%A='日曜日'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%a='水'\t%A='水曜日'\t%u='3'\t%Ou='三'\t%w='3'\t%Ow='三'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%a='日'\t%A='日曜日'\t%u='7'\t%Ou='七'\t%w='0'\t%Ow='〇'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_day_of_year() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%j='%j'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%j='%j'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%j='001'\n"), fmt, cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(SV("%j='138'\n"), fmt, cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use the global locale (fr_FR) + check(SV("%j='001'\n"), lfmt, cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(SV("%j='138'\n"), lfmt, cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use supplied locale (ja_JP). This locale has a different alternate. + check(loc, SV("%j='001'\n"), lfmt, cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, SV("%j='138'\n"), lfmt, cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_week() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%U='%U'%t%%OU='%OU'%t%%W='%W'%t%%OW='%OW'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%U='%U'%t%%OU='%OU'%t%%W='%W'%t%%OW='%OW'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%U='00'\t%OU='00'\t%W='00'\t%OW='00'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%U='20'\t%OU='20'\t%W='20'\t%OW='20'\n"), + fmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use the global locale (fr_FR) + check(SV("%U='00'\t%OU='00'\t%W='00'\t%OW='00'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%U='20'\t%OU='20'\t%W='20'\t%OW='20'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%U='00'\t%OU='00'\t%W='00'\t%OW='00'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%U='20'\t%OU='20'\t%W='20'\t%OW='20'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%U='00'\t%OU='〇'\t%W='00'\t%OW='〇'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%U='20'\t%OU='二十'\t%W='20'\t%OW='二十'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_iso_8601_week() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%g='%g'%t%%G='%G'%t%%V='%V'%t%%OV='%OV'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%g='%g'%t%%G='%G'%t%%V='%V'%t%%OV='%OV'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%g='58'\t%G='1958'\t%V='01'\t%OV='01'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%g='09'\t%G='2009'\t%V='07'\t%OV='07'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%g='58'\t%G='1958'\t%V='01'\t%OV='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%g='09'\t%G='2009'\t%V='07'\t%OV='07'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%g='58'\t%G='1958'\t%V='01'\t%OV='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%g='09'\t%G='2009'\t%V='07'\t%OV='07'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%g='58'\t%G='1958'\t%V='01'\t%OV='一'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%g='09'\t%G='2009'\t%V='07'\t%OV='七'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_date() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%D='%D'%t%%F='%F'%t%%x='%x'%t%%Ex='%Ex'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%D='%D'%t%%F='%F'%t%%x='%x'%t%%Ex='%Ex'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%D='01/01/58'\t%F='1958-01-01'\t%x='01/01/58'\t%Ex='01/01/58'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%D='02/13/09'\t%F='2009-02-13'\t%x='02/13/09'\t%Ex='02/13/09'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) +#if defined(__APPLE__) || defined(__FreeBSD__) + check(SV("%D='01/01/58'\t%F='1958-01-01'\t%x='01.01.1958'\t%Ex='01.01.1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%D='02/13/09'\t%F='2009-02-13'\t%x='13.02.2009'\t%Ex='13.02.2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else + check(SV("%D='01/01/58'\t%F='1958-01-01'\t%x='01/01/1958'\t%Ex='01/01/1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%D='02/13/09'\t%F='2009-02-13'\t%x='13/02/2009'\t%Ex='13/02/2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%D='01/01/58'\t%F='1958-01-01'\t%x='1958/01/01'\t%Ex='1958/01/01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%D='02/13/09'\t%F='2009-02-13'\t%x='2009/02/13'\t%Ex='2009/02/13'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%D='01/01/58'\t%F='1958-01-01'\t%x='1958年01月01日'\t%Ex='昭和33年01月01日'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%D='02/13/09'\t%F='2009-02-13'\t%x='2009年02月13日'\t%Ex='平成21年02月13日'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_time() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV( + "{:" + "%%H='%H'%t" + "%%OH='%OH'%t" + "%%I='%I'%t" + "%%OI='%OI'%t" + "%%M='%M'%t" + "%%OM='%OM'%t" + "%%S='%S'%t" + "%%OS='%OS'%t" + "%%p='%p'%t" + "%%R='%R'%t" + "%%T='%T'%t" + "%%r='%r'%t" + "%%X='%X'%t" + "%%EX='%EX'%t" + "%n}"); + constexpr std::basic_string_view lfmt = SV( + "{:L" + "%%H='%H'%t" + "%%OH='%OH'%t" + "%%I='%I'%t" + "%%OI='%OI'%t" + "%%M='%M'%t" + "%%OM='%OM'%t" + "%%S='%S'%t" + "%%OS='%OS'%t" + "%%p='%p'%t" + "%%R='%R'%t" + "%%T='%T'%t" + "%%r='%r'%t" + "%%X='%X'%t" + "%%EX='%EX'%t" + "%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%H='00'\t" + "%OH='00'\t" + "%I='12'\t" + "%OI='12'\t" + "%M='00'\t" + "%OM='00'\t" + "%S='00'\t" + "%OS='00'\t" + "%p='AM'\t" + "%R='00:00'\t" + "%T='00:00:00'\t" + "%r='12:00:00 AM'\t" + "%X='00:00:00'\t" + "%EX='00:00:00'\t" + "\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%H='23'\t" + "%OH='23'\t" + "%I='11'\t" + "%OI='11'\t" + "%M='31'\t" + "%OM='31'\t" + "%S='30.123'\t" + "%OS='30.123'\t" + "%p='PM'\t" + "%R='23:31'\t" + "%T='23:31:30.123'\t" + "%r='11:31:30 PM'\t" + "%X='23:31:30'\t" + "%EX='23:31:30'\t" + "\n"), + fmt, + cr::tai_time(1'613'259'090'123ms)); // 23:31:30 TAI Friday, 13 February 2009 + // Use the global locale (fr_FR) + check(SV("%H='00'\t" + "%OH='00'\t" + "%I='12'\t" + "%OI='12'\t" + "%M='00'\t" + "%OM='00'\t" + "%S='00'\t" + "%OS='00'\t" +#if defined(_AIX) + "%p='AM'\t" +#else + "%p=''\t" +#endif + "%R='00:00'\t" + "%T='00:00:00'\t" +#ifdef _WIN32 + "%r='00:00:00'\t" +#elif defined(_AIX) + "%r='12:00:00 AM'\t" +#elif defined(__APPLE__) || defined(__FreeBSD__) + "%r=''\t" +#else + "%r='12:00:00 '\t" +#endif + "%X='00:00:00'\t" + "%EX='00:00:00'\t" + "\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%H='23'\t" + "%OH='23'\t" + "%I='11'\t" + "%OI='11'\t" + "%M='31'\t" + "%OM='31'\t" + "%S='30,123'\t" + "%OS='30,123'\t" +#if defined(_AIX) + "%p='PM'\t" +#else + "%p=''\t" +#endif + "%R='23:31'\t" + "%T='23:31:30,123'\t" +#ifdef _WIN32 + "%r='23:31:30'\t" +#elif defined(_AIX) + "%r='11:31:30 PM'\t" +#elif defined(__APPLE__) || defined(__FreeBSD__) + "%r=''\t" +#else + "%r='11:31:30 '\t" +#endif + "%X='23:31:30'\t" + "%EX='23:31:30'\t" + "\n"), + lfmt, + cr::tai_time(1'613'259'090'123ms)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) + check(loc, + SV("%H='00'\t" + "%OH='00'\t" + "%I='12'\t" + "%OI='12'\t" + "%M='00'\t" + "%OM='00'\t" + "%S='00'\t" + "%OS='00'\t" +# if defined(__APPLE__) + "%p='AM'\t" +# else + "%p='午前'\t" +# endif + "%R='00:00'\t" + "%T='00:00:00'\t" +# if defined(__APPLE__) || defined(__FreeBSD__) +# if defined(__APPLE__) + "%r='12:00:00 AM'\t" +# else + "%r='12:00:00 午前'\t" +# endif + "%X='00時00分00秒'\t" + "%EX='00時00分00秒'\t" +# elif defined(_WIN32) + "%r='0:00:00'\t" + "%X='0:00:00'\t" + "%EX='0:00:00'\t" +# else + "%r='午前12:00:00'\t" + "%X='00:00:00'\t" + "%EX='00:00:00'\t" +# endif + "\n"), + lfmt, + cr::hh_mm_ss(0s)); + + check(loc, + SV("%H='23'\t" + "%OH='23'\t" + "%I='11'\t" + "%OI='11'\t" + "%M='31'\t" + "%OM='31'\t" + "%S='30.123'\t" + "%OS='30.123'\t" +# if defined(__APPLE__) + "%p='PM'\t" +# else + "%p='午後'\t" +# endif + "%R='23:31'\t" + "%T='23:31:30.123'\t" +# if defined(__APPLE__) || defined(__FreeBSD__) +# if defined(__APPLE__) + "%r='11:31:30 PM'\t" +# else + "%r='11:31:30 午後'\t" +# endif + "%X='23時31分30秒'\t" + "%EX='23時31分30秒'\t" +# elif defined(_WIN32) + "%r='23:31:30'\t" + "%X='23:31:30'\t" + "%EX='23:31:30'\t" +# else + "%r='午後11:31:30'\t" + "%X='23:31:30'\t" + "%EX='23:31:30'\t" +# endif + "\n"), + lfmt, + cr::hh_mm_ss(23h + 31min + 30s + 123ms)); +#else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) + check(loc, + SV("%H='00'\t" + "%OH='〇'\t" + "%I='12'\t" + "%OI='十二'\t" + "%M='00'\t" + "%OM='〇'\t" + "%S='00'\t" + "%OS='〇'\t" + "%p='午前'\t" + "%R='00:00'\t" + "%T='00:00:00'\t" + "%r='午前12時00分00秒'\t" + "%X='00時00分00秒'\t" + "%EX='00時00分00秒'\t" + "\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%H='23'\t" + "%OH='二十三'\t" + "%I='11'\t" + "%OI='十一'\t" + "%M='31'\t" + "%OM='三十一'\t" + "%S='30.123'\t" + "%OS='三十.123'\t" + "%p='午後'\t" + "%R='23:31'\t" + "%T='23:31:30.123'\t" + "%r='午後11時31分30秒'\t" + "%X='23時31分30秒'\t" + "%EX='23時31分30秒'\t" + "\n"), + lfmt, + cr::tai_time(1'613'259'090'123ms)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_date_time() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%c='%c'%t%%Ec='%Ec'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%c='%c'%t%%Ec='%Ec'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%c='Wed Jan 1 00:00:00 1958'\t%Ec='Wed Jan 1 00:00:00 1958'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%c='Fri Feb 13 23:31:30 2009'\t%Ec='Fri Feb 13 23:31:30 2009'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check( +// https://sourceware.org/bugzilla/show_bug.cgi?id=24054 +#if defined(__powerpc__) && defined(__linux__) + SV("%c='mer. 01 janv. 1958 00:00:00 TAI'\t%Ec='mer. 01 janv. 1958 00:00:00 TAI'\n"), +#elif defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29 + SV("%c='mer. 01 janv. 1958 00:00:00 GMT'\t%Ec='mer. 01 janv. 1958 00:00:00 GMT'\n"), +#elif defined(_AIX) + SV("%c=' 1 janvier 1958 à 00:00:00 TAI'\t%Ec=' 1 janvier 1958 à 00:00:00 TAI'\n"), +#elif defined(__APPLE__) + SV("%c='Jeu 1 jan 00:00:00 1958'\t%Ec='Jeu 1 jan 00:00:00 1958'\n"), +#elif defined(_WIN32) + SV("%c='01/01/1958 00:00:00'\t%Ec='01/01/1958 00:00:00'\n"), +#elif defined(__FreeBSD__) + SV("%c='mer. 1 janv. 00:00:00 1958'\t%Ec='mer. 1 janv. 00:00:00 1958'\n"), +#else + SV("%c='mer. 01 janv. 1958 00:00:00'\t%Ec='mer. 01 janv. 1958 00:00:00'\n"), +#endif + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check( +// https://sourceware.org/bugzilla/show_bug.cgi?id=24054 +#if defined(__powerpc__) && defined(__linux__) + SV("%c='ven. 13 févr. 2009 23:31:30 TAI'\t%Ec='ven. 13 févr. 2009 23:31:30 TAI'\n"), +#elif defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29 + SV("%c='ven. 13 févr. 2009 23:31:30 GMT'\t%Ec='ven. 13 févr. 2009 23:31:30 GMT'\n"), +#elif defined(_AIX) + SV("%c='13 février 2009 à 23:31:30 TAI'\t%Ec='13 février 2009 à 23:31:30 TAI'\n"), +#elif defined(__APPLE__) + SV("%c='Ven 13 fév 23:31:30 2009'\t%Ec='Ven 13 fév 23:31:30 2009'\n"), +#elif defined(_WIN32) + SV("%c='13/02/2009 23:31:30'\t%Ec='13/02/2009 23:31:30'\n"), +#elif defined(__FreeBSD__) + SV("%c='ven. 13 févr. 23:31:30 2009'\t%Ec='ven. 13 févr. 23:31:30 2009'\n"), +#else + SV("%c='ven. 13 févr. 2009 23:31:30'\t%Ec='ven. 13 févr. 2009 23:31:30'\n"), +#endif + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate.a +#if defined(__APPLE__) || defined(__FreeBSD__) + check(loc, + SV("%c='水 1/ 1 00:00:00 1958'\t%Ec='水 1/ 1 00:00:00 1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, + SV("%c='金 2/13 23:31:30 2009'\t%Ec='金 2/13 23:31:30 2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#elif defined(_AIX) // defined(__APPLE__)|| defined(__FreeBSD__) + check(loc, + SV("%c='1958年01月 1日 00:00:00 TAI'\t%Ec='1958年01月 1日 00:00:00 TAI'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, + SV("%c='2009年02月13日 23:31:30 TAI'\t%Ec='2009年02月13日 23:31:30 TAI'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#elif defined(_WIN32) // defined(__APPLE__)|| defined(__FreeBSD__) + check(loc, + SV("%c='1958/01/01 0:00:00'\t%Ec='1958/01/01 0:00:00'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, + SV("%c='2009/02/13 23:31:30'\t%Ec='2009/02/13 23:31:30'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(__APPLE__)|| defined(__FreeBSD__) + check(loc, + SV("%c='1958年01月01日 00時00分00秒'\t%Ec='昭和33年01月01日 00時00分00秒'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%c='2009年02月13日 23時31分30秒'\t%Ec='平成21年02月13日 23時31分30秒'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(__APPLE__)|| defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_time_zone() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%z='%z'%t%%Ez='%Ez'%t%%Oz='%Oz'%t%%Z='%Z'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%z='%z'%t%%Ez='%Ez'%t%%Oz='%Oz'%t%%Z='%Z'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='TAI'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + // Use the global locale (fr_FR) + check(SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='TAI'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + // Use supplied locale (ja_JP). + check(loc, + SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='TAI'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values() { + test_valid_values_year(); + test_valid_values_month(); + test_valid_values_day(); + test_valid_values_weekday(); + test_valid_values_day_of_year(); + test_valid_values_week(); + test_valid_values_iso_8601_week(); + test_valid_values_date(); + test_valid_values_time(); + test_valid_values_date_time(); + test_valid_values_time_zone(); +} + +template +static void test() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + test_no_chrono_specs(); + test_valid_values(); + check_invalid_types( + {SV("a"), SV("A"), SV("b"), SV("B"), SV("c"), SV("C"), SV("d"), SV("D"), SV("e"), SV("F"), SV("g"), + SV("G"), SV("h"), SV("H"), SV("I"), SV("j"), SV("m"), SV("M"), SV("p"), SV("r"), SV("R"), SV("S"), + SV("T"), SV("u"), SV("U"), SV("V"), SV("w"), SV("W"), SV("x"), SV("X"), SV("y"), SV("Y"), SV("z"), + SV("Z"), SV("Ec"), SV("EC"), SV("Ex"), SV("EX"), SV("Ey"), SV("EY"), SV("Ez"), SV("Od"), SV("Oe"), SV("OH"), + SV("OI"), SV("Om"), SV("OM"), SV("OS"), SV("Ou"), SV("OU"), SV("OV"), SV("Ow"), SV("OW"), SV("Oy"), SV("Oz")}, + cr::tai_seconds(0s)); + + check_exception("The format specifier expects a '%' or a '}'", SV("{:A"), cr::tai_seconds(0s)); + check_exception("The chrono specifiers contain a '{'", SV("{:%%{"), cr::tai_seconds(0s)); + check_exception("End of input while parsing a conversion specifier", SV("{:%"), cr::tai_seconds(0s)); + check_exception("End of input while parsing the modifier E", SV("{:%E"), cr::tai_seconds(0s)); + check_exception("End of input while parsing the modifier O", SV("{:%O"), cr::tai_seconds(0s)); + + // Precision not allowed + check_exception("The format specifier expects a '%' or a '}'", SV("{:.3}"), cr::tai_seconds(0s)); +} + +int main(int, char**) { + test(); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + + return 0; +} diff --git a/libcxx/test/support/concat_macros.h b/libcxx/test/support/concat_macros.h index d7340b8faf6e56..50b65621973927 100644 --- a/libcxx/test/support/concat_macros.h +++ b/libcxx/test/support/concat_macros.h @@ -11,6 +11,7 @@ #include #include +#include #include "assert_macros.h" #include "test_macros.h" @@ -134,6 +135,10 @@ OutIt test_transcode(InIt first, InIt last, OutIt out_it) { return out_it; } +std::ostream& operator<<(std::ostream& os, const std::source_location& loc) { + return os << loc.file_name() << ':' << loc.line() << ':' << loc.column(); +} + template concept test_streamable = requires(std::stringstream& stream, T&& value) { stream << value; }; >From 71536e015e10b5c878e9e7562bf6e7bf4981150a Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Mon, 3 Feb 2025 20:40:16 +0100 Subject: [PATCH 2/2] CI fixes --- libcxx/include/__chrono/convert_to_tm.h | 1 + libcxx/include/__chrono/formatter.h | 4 ++-- libcxx/include/__chrono/tai_clock.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__chrono/convert_to_tm.h b/libcxx/include/__chrono/convert_to_tm.h index 934293ce382345..d9ccf693160d29 100644 --- a/libcxx/include/__chrono/convert_to_tm.h +++ b/libcxx/include/__chrono/convert_to_tm.h @@ -36,6 +36,7 @@ #include <__config> #include <__format/format_error.h> #include <__memory/addressof.h> +#include <__type_traits/common_type.h> #include <__type_traits/is_convertible.h> #include <__type_traits/is_specialization.h> #include diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h index 753a824a3c50d7..13bcb717291f69 100644 --- a/libcxx/include/__chrono/formatter.h +++ b/libcxx/include/__chrono/formatter.h @@ -232,12 +232,12 @@ _LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const # if _LIBCPP_HAS_EXPERIMENTAL_TZDB if constexpr (same_as<_Tp, chrono::sys_info>) return {__value.abbrev, __value.offset}; +# if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM else if constexpr (__is_time_point<_Tp> && requires { requires same_as; }) return {"TAI", chrono::seconds{0}}; -# if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) return __formatter::__convert_to_time_zone(__value.get_info()); -# endif +# endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM else # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB return {"UTC", chrono::seconds{0}}; diff --git a/libcxx/include/__chrono/tai_clock.h b/libcxx/include/__chrono/tai_clock.h index 18ba329b7b8fb4..17c637d2b2c8c8 100644 --- a/libcxx/include/__chrono/tai_clock.h +++ b/libcxx/include/__chrono/tai_clock.h @@ -14,6 +14,7 @@ // Enable the contents of the header only when libc++ was built with experimental features enabled. #if _LIBCPP_HAS_EXPERIMENTAL_TZDB +# include <__assert> # include <__chrono/duration.h> # include <__chrono/time_point.h> # include <__chrono/utc_clock.h> From libcxx-commits at lists.llvm.org Mon Feb 3 11:41:33 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 11:41:33 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][TZDB] Fixes %z escaping. (PR #125399) In-Reply-To: Message-ID: <67a11bed.170a0220.25ea6f.b3e8@mx.google.com> https://github.com/mordante milestoned https://github.com/llvm/llvm-project/pull/125399 From libcxx-commits at lists.llvm.org Mon Feb 3 11:54:22 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Mon, 03 Feb 2025 11:54:22 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libcxx] replaces `sqrt(complex)` implementation with builtin (PR #122391) In-Reply-To: Message-ID: <67a11eee.170a0220.80fe3.49ea@mx.google.com> https://github.com/mordante commented: > This significantly improves the accuracy of the function. > > Fixes #122172 Thanks for working on this! Can you add the examples from the bug report to the tests? https://github.com/llvm/llvm-project/pull/122391 From libcxx-commits at lists.llvm.org Mon Feb 3 12:54:29 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 12:54:29 -0800 (PST) Subject: [libcxx-commits] =?utf-8?q?=5Blibcxx=5D_=5Blibc++=5D_Provide_size?= =?utf-8?q?d_deallocation_declarations_even_when_the_compil=E2=80=A6_=28PR?= =?utf-8?b?ICMxMjU1Nzcp?= In-Reply-To: Message-ID: <67a12d05.630a0220.4babe.28c5@mx.google.com> https://github.com/ldionne milestoned https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 12:54:29 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 12:54:29 -0800 (PST) Subject: [libcxx-commits] =?utf-8?q?=5Blibcxx=5D_=5Blibc++=5D_Provide_size?= =?utf-8?q?d_deallocation_declarations_even_when_the_compil=E2=80=A6_=28PR?= =?utf-8?b?ICMxMjU1Nzcp?= Message-ID: https://github.com/ldionne created https://github.com/llvm/llvm-project/pull/125577 …er doesn't support sized deallocation After ef804d8f9b4, we stopped providing the declaration of sized deallocation functions unless the compiler provides support for the language feature. In reality, we can still provide the declarations of global operator delete for users who want to call these operators directly without going through the compiler rewrite. >From 35aeeb6e70b63999f610e479b4d11db20213551d Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 3 Feb 2025 15:47:01 -0500 Subject: [PATCH] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation After ef804d8f9b4, we stopped providing the declaration of sized deallocation functions unless the compiler provides support for the language feature. In reality, we can still provide the declarations of global operator delete for users who want to call these operators directly without going through the compiler rewrite. --- libcxx/include/__new/global_new_delete.h | 2 +- ...zed_delete.fno-sized-deallocation.pass.cpp | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp diff --git a/libcxx/include/__new/global_new_delete.h b/libcxx/include/__new/global_new_delete.h index 96510ab56b00b5..3d1f7b6f3d2409 100644 --- a/libcxx/include/__new/global_new_delete.h +++ b/libcxx/include/__new/global_new_delete.h @@ -25,7 +25,7 @@ # define _THROW_BAD_ALLOC #endif -#if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L +#if _LIBCPP_STD_VER >= 14 # define _LIBCPP_HAS_SIZED_DEALLOCATION 1 #else # define _LIBCPP_HAS_SIZED_DEALLOCATION 0 diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp new file mode 100644 index 00000000000000..daa0374fd28125 --- /dev/null +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Ensure that libc++ still provides the declaration of sized operator delete even +// when sized deallocation support is disabled at the language level, since it should +// still be valid to call these operators explicitly (as opposed to via a compiler +// rewrite of a delete expression). + +// UNSUPPORTED: c++03, c++11 + +// ADDITIONAL_COMPILE_FLAGS: -fno-sized-deallocation + +// Sized deallocation support was introduced in LLVM 11 +// XFAIL: using-built-library-before-llvm-11 + +#include + +int main(int, char**) { + void* p = ::operator new(10); + ::operator delete(p, 10); + return 0; +} From libcxx-commits at lists.llvm.org Mon Feb 3 12:54:38 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 12:54:38 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a12d0e.170a0220.95e48.029b@mx.google.com> https://github.com/ldionne edited https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 12:54:43 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 12:54:43 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a12d13.170a0220.1706c4.5cdd@mx.google.com> https://github.com/ldionne edited https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 12:54:50 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 12:54:50 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a12d1a.630a0220.d742a.1d78@mx.google.com> https://github.com/ldionne edited https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 12:55:00 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Mon, 03 Feb 2025 12:55:00 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a12d24.170a0220.35b788.f8b6@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-libcxx Author: Louis Dionne (ldionne)
Changes After ef804d8f9b4, we stopped providing the declaration of sized deallocation functions unless the compiler provides support for the language feature. In reality, we can still provide the declarations of global operator delete for users who want to call these operators directly without going through the compiler rewrite. --- Full diff: https://github.com/llvm/llvm-project/pull/125577.diff 2 Files Affected: - (modified) libcxx/include/__new/global_new_delete.h (+1-1) - (added) libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp (+27) ``````````diff diff --git a/libcxx/include/__new/global_new_delete.h b/libcxx/include/__new/global_new_delete.h index 96510ab56b00b5a..3d1f7b6f3d24090 100644 --- a/libcxx/include/__new/global_new_delete.h +++ b/libcxx/include/__new/global_new_delete.h @@ -25,7 +25,7 @@ # define _THROW_BAD_ALLOC #endif -#if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L +#if _LIBCPP_STD_VER >= 14 # define _LIBCPP_HAS_SIZED_DEALLOCATION 1 #else # define _LIBCPP_HAS_SIZED_DEALLOCATION 0 diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp new file mode 100644 index 000000000000000..daa0374fd28125d --- /dev/null +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Ensure that libc++ still provides the declaration of sized operator delete even +// when sized deallocation support is disabled at the language level, since it should +// still be valid to call these operators explicitly (as opposed to via a compiler +// rewrite of a delete expression). + +// UNSUPPORTED: c++03, c++11 + +// ADDITIONAL_COMPILE_FLAGS: -fno-sized-deallocation + +// Sized deallocation support was introduced in LLVM 11 +// XFAIL: using-built-library-before-llvm-11 + +#include + +int main(int, char**) { + void* p = ::operator new(10); + ::operator delete(p, 10); + return 0; +} ``````````
https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 12:55:20 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 12:55:20 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a12d38.170a0220.3135b8.04ba@mx.google.com> ldionne wrote: Another view point on this is that the library should not provide the declaration when the language feature is turned off, but I'm tempted to decouple the two. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 12:56:26 2025 From: libcxx-commits at lists.llvm.org (Konstantin Varlamov via libcxx-commits) Date: Mon, 03 Feb 2025 12:56:26 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a12d7a.a70a0220.34e3b8.33d9@mx.google.com> https://github.com/var-const approved this pull request. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 12:57:46 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Mon, 03 Feb 2025 12:57:46 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a12dca.a70a0220.282faa.3a2e@mx.google.com> github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning:
You can test this locally with the following command: ``````````bash git-clang-format --diff c7c7eabc7fc42433ed6a0a93ea14f279ad8d37af 35aeeb6e70b63999f610e479b4d11db20213551d --extensions h,cpp -- libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp libcxx/include/__new/global_new_delete.h ``````````
View the diff from clang-format here. ``````````diff diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp index daa0374fd2..f6145cb1eb 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp @@ -21,7 +21,7 @@ #include int main(int, char**) { - void* p = ::operator new(10); - ::operator delete(p, 10); - return 0; + void* p = ::operator new(10); + ::operator delete(p, 10); + return 0; } ``````````
https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 13:13:12 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 13:13:12 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a13168.170a0220.11fc23.0a56@mx.google.com> https://github.com/philnik777 requested changes to this pull request. I don't think this is a good idea. If sized deallocation is disabled there tends to be a reason for that - most likely that they're not available. This just pushes the diagnostic to be a linker error instead most likely, which isn't great. So unless there is a good use-case for sized deallocation being disabled at the language level but should be provided by the library I don't think we should go forward with this. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 13:26:28 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 13:26:28 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036) (PR #125587) In-Reply-To: Message-ID: <67a13484.050a0220.1d5370.1c9b@mx.google.com> https://github.com/ldionne milestoned https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Mon Feb 3 13:26:29 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 13:26:29 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036) (PR #125587) Message-ID: https://github.com/ldionne created https://github.com/llvm/llvm-project/pull/125587 This reverts commit 5f2389d4. That commit started checking whether was a valid include, however codebases are free to have such a header on their search path, which breaks compilation. LLVM libc should instead provide a more standard way of getting configuration macros like __LLVM_LIBC__. >From f27c95a4c4429e3fe8efbff210fdd52847b23db4 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 3 Feb 2025 16:23:12 -0500 Subject: [PATCH] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036)" This reverts commit 5f2389d4. That commit started checking whether was a valid include, however codebases are free to have such a header on their search path, which breaks compilation. LLVM libc should instead provide a more standard way of getting configuration macros like __LLVM_LIBC__. --- libcxx/include/__configuration/platform.h | 9 +++------ libcxx/include/__random/binomial_distribution.h | 3 +-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/libcxx/include/__configuration/platform.h b/libcxx/include/__configuration/platform.h index 2a92ce209b91f8..27f68d04e8a8d9 100644 --- a/libcxx/include/__configuration/platform.h +++ b/libcxx/include/__configuration/platform.h @@ -30,18 +30,15 @@ // ... add new file formats here ... #endif -// To detect which libc we're using -#if __has_include() -# include -#endif - +// Need to detect which libc we're using if we're on Linux. #if defined(__linux__) +# include # if defined(__GLIBC_PREREQ) # define _LIBCPP_GLIBC_PREREQ(a, b) __GLIBC_PREREQ(a, b) # else # define _LIBCPP_GLIBC_PREREQ(a, b) 0 # endif // defined(__GLIBC_PREREQ) -#endif +#endif // defined(__linux__) #ifndef __BYTE_ORDER__ # error \ diff --git a/libcxx/include/__random/binomial_distribution.h b/libcxx/include/__random/binomial_distribution.h index 9538c15e2dc97b..47790b674db588 100644 --- a/libcxx/include/__random/binomial_distribution.h +++ b/libcxx/include/__random/binomial_distribution.h @@ -97,8 +97,7 @@ class _LIBCPP_TEMPLATE_VIS binomial_distribution { } }; -// The LLVM C library provides this with conflicting `noexcept` attributes. -#if !defined(_LIBCPP_MSVCRT_LIKE) && !defined(__LLVM_LIBC__) +#ifndef _LIBCPP_MSVCRT_LIKE extern "C" double lgamma_r(double, int*); #endif From libcxx-commits at lists.llvm.org Mon Feb 3 13:26:43 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 13:26:43 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036) (PR #125587) In-Reply-To: Message-ID: <67a13493.170a0220.1d5227.58b7@mx.google.com> ldionne wrote: CF https://github.com/llvm/llvm-project/pull/102036#discussion_r1917369024 https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Mon Feb 3 13:26:49 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Mon, 03 Feb 2025 13:26:49 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036) (PR #125587) In-Reply-To: Message-ID: <67a13499.170a0220.39673.0a9e@mx.google.com> https://github.com/ldionne edited https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Mon Feb 3 13:27:02 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Mon, 03 Feb 2025 13:27:02 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036) (PR #125587) In-Reply-To: Message-ID: <67a134a6.a70a0220.18971e.53de@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-libcxx Author: Louis Dionne (ldionne)
Changes This reverts commit 5f2389d4. That commit started checking whether <features.h> was a valid include, however codebases are free to have such a header on their search path, which breaks compilation. LLVM libc should instead provide a more standard way of getting configuration macros like __LLVM_LIBC__. --- Full diff: https://github.com/llvm/llvm-project/pull/125587.diff 2 Files Affected: - (modified) libcxx/include/__configuration/platform.h (+3-6) - (modified) libcxx/include/__random/binomial_distribution.h (+1-2) ``````````diff diff --git a/libcxx/include/__configuration/platform.h b/libcxx/include/__configuration/platform.h index 2a92ce209b91f8b..27f68d04e8a8d9c 100644 --- a/libcxx/include/__configuration/platform.h +++ b/libcxx/include/__configuration/platform.h @@ -30,18 +30,15 @@ // ... add new file formats here ... #endif -// To detect which libc we're using -#if __has_include() -# include -#endif - +// Need to detect which libc we're using if we're on Linux. #if defined(__linux__) +# include # if defined(__GLIBC_PREREQ) # define _LIBCPP_GLIBC_PREREQ(a, b) __GLIBC_PREREQ(a, b) # else # define _LIBCPP_GLIBC_PREREQ(a, b) 0 # endif // defined(__GLIBC_PREREQ) -#endif +#endif // defined(__linux__) #ifndef __BYTE_ORDER__ # error \ diff --git a/libcxx/include/__random/binomial_distribution.h b/libcxx/include/__random/binomial_distribution.h index 9538c15e2dc97b5..47790b674db5882 100644 --- a/libcxx/include/__random/binomial_distribution.h +++ b/libcxx/include/__random/binomial_distribution.h @@ -97,8 +97,7 @@ class _LIBCPP_TEMPLATE_VIS binomial_distribution { } }; -// The LLVM C library provides this with conflicting `noexcept` attributes. -#if !defined(_LIBCPP_MSVCRT_LIKE) && !defined(__LLVM_LIBC__) +#ifndef _LIBCPP_MSVCRT_LIKE extern "C" double lgamma_r(double, int*); #endif ``````````
https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Mon Feb 3 13:30:49 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 13:30:49 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036) (PR #125587) In-Reply-To: Message-ID: <67a13589.170a0220.31166a.fdba@mx.google.com> philnik777 wrote: Would it make sense to partially revert? IIUC this still works when targeting linux with the LLVM libc, so we could just revert the inclusion of `` if available. https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Mon Feb 3 13:34:17 2025 From: libcxx-commits at lists.llvm.org (Joseph Huber via libcxx-commits) Date: Mon, 03 Feb 2025 13:34:17 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036) (PR #125587) In-Reply-To: Message-ID: <67a13659.050a0220.31c8f.298a@mx.google.com> jhuber6 wrote: I'd prefer a partial revert because this would break the GPU libc++ build. (Sorry I got sidetracked about setting up that build on a bot. I need to get @jplehr or @Artem-B to help me with that). We still can't run the tests clean, but a build is better than nothing. https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Mon Feb 3 13:36:48 2025 From: libcxx-commits at lists.llvm.org (Joseph Huber via libcxx-commits) Date: Mon, 03 Feb 2025 13:36:48 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036) (PR #125587) In-Reply-To: Message-ID: <67a136f0.a70a0220.2a172b.4572@mx.google.com> jhuber6 wrote: Might need to check for `__AMDGPU__` and `__NVPTX__` or something, since this is what lets us use `lgamma` and stuff. alternatively we could replace this with a cmake check that just sees if the environment can call `lgamma_r`. https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Mon Feb 3 14:19:57 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Mon, 03 Feb 2025 14:19:57 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::equal for vector::iterator (PR #121084) In-Reply-To: Message-ID: <67a1410d.050a0220.1cf685.59b3@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/121084 >From 2b9442a880fef482c154527a86fb69bad11c888f Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Tue, 24 Dec 2024 18:24:39 -0500 Subject: [PATCH] Optimize ranges::equal for vector::iterator --- libcxx/docs/ReleaseNotes/21.rst | 2 + libcxx/include/__algorithm/equal.h | 160 +++++++++++ libcxx/include/__bit_reference | 135 +--------- libcxx/include/bitset | 1 + .../benchmarks/algorithms/equal.bench.cpp | 51 ++++ .../alg.nonmodifying/alg.equal/equal.pass.cpp | 35 +++ .../alg.equal/ranges.equal.pass.cpp | 251 +++++++++++------- 7 files changed, 418 insertions(+), 217 deletions(-) diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad3942..da5b541f9e20a2 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -46,6 +46,8 @@ Improvements and New Features - The ``std::ranges::{copy, copy_n, copy_backward}`` algorithms have been optimized for ``std::vector::iterator``\s, resulting in a performance improvement of up to 2000x. +- The ``std::ranges::equal`` algorithm has been optimized for ``std::vector::iterator``, resulting in a performance + improvement of up to 188x. Deprecations and Removals ------------------------- diff --git a/libcxx/include/__algorithm/equal.h b/libcxx/include/__algorithm/equal.h index a276bb9954c9bb..c7f5ed2359ad79 100644 --- a/libcxx/include/__algorithm/equal.h +++ b/libcxx/include/__algorithm/equal.h @@ -11,19 +11,27 @@ #define _LIBCPP___ALGORITHM_EQUAL_H #include <__algorithm/comp.h> +#include <__algorithm/min.h> #include <__algorithm/unwrap_iter.h> #include <__config> #include <__functional/identity.h> +#include <__fwd/bit_reference.h> #include <__iterator/distance.h> #include <__iterator/iterator_traits.h> +#include <__memory/pointer_traits.h> #include <__string/constexpr_c_functions.h> #include <__type_traits/desugars_to.h> #include <__type_traits/enable_if.h> #include <__type_traits/invoke.h> #include <__type_traits/is_equality_comparable.h> +#include <__type_traits/is_same.h> #include <__type_traits/is_volatile.h> #include <__utility/move.h> +#if _LIBCPP_STD_VER >= 20 +# include <__functional/ranges_operations.h> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif @@ -33,6 +41,132 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +template +[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_unaligned( + __bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { + using _It = __bit_iterator<_Cp, _IC1>; + using difference_type = typename _It::difference_type; + using __storage_type = typename _It::__storage_type; + + const int __bits_per_word = _It::__bits_per_word; + difference_type __n = __last1 - __first1; + if (__n > 0) { + // do first word + if (__first1.__ctz_ != 0) { + unsigned __clz_f = __bits_per_word - __first1.__ctz_; + difference_type __dn = std::min(static_cast(__clz_f), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __storage_type __b = *__first1.__seg_ & __m; + unsigned __clz_r = __bits_per_word - __first2.__ctz_; + __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r); + __m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn)); + if (__first2.__ctz_ > __first1.__ctz_) { + if ((*__first2.__seg_ & __m) != (__b << (__first2.__ctz_ - __first1.__ctz_))) + return false; + } else { + if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ - __first2.__ctz_))) + return false; + } + __first2.__seg_ += (__ddn + __first2.__ctz_) / __bits_per_word; + __first2.__ctz_ = static_cast((__ddn + __first2.__ctz_) % __bits_per_word); + __dn -= __ddn; + if (__dn > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __dn); + if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ + __ddn))) + return false; + __first2.__ctz_ = static_cast(__dn); + } + ++__first1.__seg_; + // __first1.__ctz_ = 0; + } + // __first1.__ctz_ == 0; + // do middle words + unsigned __clz_r = __bits_per_word - __first2.__ctz_; + __storage_type __m = ~__storage_type(0) << __first2.__ctz_; + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_) { + __storage_type __b = *__first1.__seg_; + if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_)) + return false; + ++__first2.__seg_; + if ((*__first2.__seg_ & ~__m) != (__b >> __clz_r)) + return false; + } + // do last word + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __b = *__first1.__seg_ & __m; + __storage_type __dn = std::min(__n, static_cast(__clz_r)); + __m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn)); + if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_)) + return false; + __first2.__seg_ += (__dn + __first2.__ctz_) / __bits_per_word; + __first2.__ctz_ = static_cast((__dn + __first2.__ctz_) % __bits_per_word); + __n -= __dn; + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + if ((*__first2.__seg_ & __m) != (__b >> __dn)) + return false; + } + } + } + return true; +} + +template +[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_aligned( + __bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { + using _It = __bit_iterator<_Cp, _IC1>; + using difference_type = typename _It::difference_type; + using __storage_type = typename _It::__storage_type; + + const int __bits_per_word = _It::__bits_per_word; + difference_type __n = __last1 - __first1; + if (__n > 0) { + // do first word + if (__first1.__ctz_ != 0) { + unsigned __clz = __bits_per_word - __first1.__ctz_; + difference_type __dn = std::min(static_cast(__clz), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz - __dn)); + if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m)) + return false; + ++__first2.__seg_; + ++__first1.__seg_; + // __first1.__ctz_ = 0; + // __first2.__ctz_ = 0; + } + // __first1.__ctz_ == 0; + // __first2.__ctz_ == 0; + // do middle words + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_, ++__first2.__seg_) + if (*__first2.__seg_ != *__first1.__seg_) + return false; + // do last word + if (__n > 0) { + __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m)) + return false; + } + } + return true; +} + +template ::value, int> = 0> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl( + __bit_iterator<_Cp, _IC1> __first1, + __bit_iterator<_Cp, _IC1> __last1, + __bit_iterator<_Cp, _IC2> __first2, + _BinaryPredicate) { + if (__first1.__ctz_ == __first2.__ctz_) + return std::__equal_aligned(__first1, __last1, __first2); + return std::__equal_unaligned(__first1, __last1, __first2); +} + template [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl( _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate& __pred) { @@ -94,6 +228,32 @@ __equal_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _Up*, _Pred&, _Proj1&, return std::__constexpr_memcmp_equal(__first1, __first2, __element_count(__last1 - __first1)); } +template ::value +# if _LIBCPP_STD_VER >= 20 + || is_same<_Pred, ranges::equal_to>::value +# endif + ) && + __desugars_to_v<__equal_tag, _Pred, bool, bool> && __is_identity<_Proj1>::value && + __is_identity<_Proj2>::value, + int> = 0> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_impl( + __bit_iterator<_Cp, _IC1> __first1, + __bit_iterator<_Cp, _IC1> __last1, + __bit_iterator<_Cp, _IC2> __first2, + __bit_iterator<_Cp, _IC2>, + _Pred&, + _Proj1&, + _Proj2&) { + __equal_to __pred; + return std::__equal_iter_impl(__first1, __last1, __first2, __pred); +} + template [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool equal(_InputIterator1 __first1, diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c39805..d682789c2a32bf 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -12,7 +12,9 @@ #include <__algorithm/copy.h> #include <__algorithm/copy_backward.h> +#include <__algorithm/comp.h> #include <__algorithm/copy_n.h> +#include <__algorithm/equal.h> #include <__algorithm/min.h> #include <__bit/countr.h> #include <__compare/ordering.h> @@ -24,7 +26,9 @@ #include <__memory/construct_at.h> #include <__memory/pointer_traits.h> #include <__type_traits/conditional.h> +#include <__type_traits/enable_if.h> #include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_same.h> #include <__type_traits/void_t.h> #include <__utility/pair.h> #include <__utility/swap.h> @@ -420,127 +424,6 @@ rotate(__bit_iterator<_Cp, false> __first, __bit_iterator<_Cp, false> __middle, return __r; } -// equal - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_unaligned( - __bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { - using _It = __bit_iterator<_Cp, _IC1>; - using difference_type = typename _It::difference_type; - using __storage_type = typename _It::__storage_type; - - const int __bits_per_word = _It::__bits_per_word; - difference_type __n = __last1 - __first1; - if (__n > 0) { - // do first word - if (__first1.__ctz_ != 0) { - unsigned __clz_f = __bits_per_word - __first1.__ctz_; - difference_type __dn = std::min(static_cast(__clz_f), __n); - __n -= __dn; - __storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - __storage_type __b = *__first1.__seg_ & __m; - unsigned __clz_r = __bits_per_word - __first2.__ctz_; - __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r); - __m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn)); - if (__first2.__ctz_ > __first1.__ctz_) { - if ((*__first2.__seg_ & __m) != (__b << (__first2.__ctz_ - __first1.__ctz_))) - return false; - } else { - if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ - __first2.__ctz_))) - return false; - } - __first2.__seg_ += (__ddn + __first2.__ctz_) / __bits_per_word; - __first2.__ctz_ = static_cast((__ddn + __first2.__ctz_) % __bits_per_word); - __dn -= __ddn; - if (__dn > 0) { - __m = ~__storage_type(0) >> (__bits_per_word - __dn); - if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ + __ddn))) - return false; - __first2.__ctz_ = static_cast(__dn); - } - ++__first1.__seg_; - // __first1.__ctz_ = 0; - } - // __first1.__ctz_ == 0; - // do middle words - unsigned __clz_r = __bits_per_word - __first2.__ctz_; - __storage_type __m = ~__storage_type(0) << __first2.__ctz_; - for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_) { - __storage_type __b = *__first1.__seg_; - if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_)) - return false; - ++__first2.__seg_; - if ((*__first2.__seg_ & ~__m) != (__b >> __clz_r)) - return false; - } - // do last word - if (__n > 0) { - __m = ~__storage_type(0) >> (__bits_per_word - __n); - __storage_type __b = *__first1.__seg_ & __m; - __storage_type __dn = std::min(__n, static_cast(__clz_r)); - __m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn)); - if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_)) - return false; - __first2.__seg_ += (__dn + __first2.__ctz_) / __bits_per_word; - __first2.__ctz_ = static_cast((__dn + __first2.__ctz_) % __bits_per_word); - __n -= __dn; - if (__n > 0) { - __m = ~__storage_type(0) >> (__bits_per_word - __n); - if ((*__first2.__seg_ & __m) != (__b >> __dn)) - return false; - } - } - } - return true; -} - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_aligned( - __bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { - using _It = __bit_iterator<_Cp, _IC1>; - using difference_type = typename _It::difference_type; - using __storage_type = typename _It::__storage_type; - - const int __bits_per_word = _It::__bits_per_word; - difference_type __n = __last1 - __first1; - if (__n > 0) { - // do first word - if (__first1.__ctz_ != 0) { - unsigned __clz = __bits_per_word - __first1.__ctz_; - difference_type __dn = std::min(static_cast(__clz), __n); - __n -= __dn; - __storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz - __dn)); - if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m)) - return false; - ++__first2.__seg_; - ++__first1.__seg_; - // __first1.__ctz_ = 0; - // __first2.__ctz_ = 0; - } - // __first1.__ctz_ == 0; - // __first2.__ctz_ == 0; - // do middle words - for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_, ++__first2.__seg_) - if (*__first2.__seg_ != *__first1.__seg_) - return false; - // do last word - if (__n > 0) { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m)) - return false; - } - } - return true; -} - -template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool -equal(__bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { - if (__first1.__ctz_ == __first2.__ctz_) - return std::__equal_aligned(__first1, __last1, __first2); - return std::__equal_unaligned(__first1, __last1, __first2); -} - template class __bit_iterator { public: @@ -769,9 +652,13 @@ private: template _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool __equal_unaligned(__bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>); - template - _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool - equal(__bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>); + template ::value, int> > + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool __equal_iter_impl( + __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>, _BinaryPredicate); template _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, _IC> __find_bool(__bit_iterator<_Dp, _IC>, typename __size_difference_type_traits<_Dp>::size_type); diff --git a/libcxx/include/bitset b/libcxx/include/bitset index a20842985b3d59..afc44daa9ed380 100644 --- a/libcxx/include/bitset +++ b/libcxx/include/bitset @@ -132,6 +132,7 @@ template struct hash>; # include <__algorithm/copy.h> # include <__algorithm/copy_backward.h> # include <__algorithm/count.h> +# include <__algorithm/equal.h> # include <__algorithm/fill.h> # include <__algorithm/fill_n.h> # include <__algorithm/find.h> diff --git a/libcxx/test/benchmarks/algorithms/equal.bench.cpp b/libcxx/test/benchmarks/algorithms/equal.bench.cpp index 2dc11585c15c7f..328b39608607ed 100644 --- a/libcxx/test/benchmarks/algorithms/equal.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/equal.bench.cpp @@ -45,4 +45,55 @@ static void bm_ranges_equal(benchmark::State& state) { } BENCHMARK(bm_ranges_equal)->DenseRange(1, 8)->Range(16, 1 << 20); +static void bm_ranges_equal_vb_aligned(benchmark::State& state) { + auto n = state.range(); + std::vector vec1(n, true); + std::vector vec2(n, true); + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::equal(vec1, vec2)); + benchmark::DoNotOptimize(&vec1); + benchmark::DoNotOptimize(&vec2); + } +} + +static void bm_ranges_equal_vb_unaligned(benchmark::State& state) { + auto n = state.range(); + std::vector vec1(n, true); + std::vector vec2(n + 8, true); + auto beg1 = std::ranges::begin(vec1); + auto end1 = std::ranges::end(vec1); + auto beg2 = std::ranges::begin(vec2) + 4; + auto end2 = std::ranges::end(vec2) - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::equal(beg1, end1, beg2, end2)); + benchmark::DoNotOptimize(&vec1); + benchmark::DoNotOptimize(&vec2); + } +} + +// Test std::ranges::equal for vector::iterator +BENCHMARK(bm_ranges_equal_vb_aligned)->RangeMultiplier(4)->Range(8, 1 << 20); +BENCHMARK(bm_ranges_equal_vb_unaligned)->Range(8, 1 << 20); + +static void bm_equal_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector vec1(n, true); + std::vector vec2(aligned ? n : n + 8, true); + auto beg1 = vec1.begin(); + auto end1 = vec1.end(); + auto beg2 = aligned ? vec2.begin() : vec2.begin() + 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::equal(beg1, end1, beg2)); + benchmark::DoNotOptimize(&vec1); + benchmark::DoNotOptimize(&vec2); + } +} + +static void bm_equal_vb_aligned(benchmark::State& state) { bm_equal_vb(state, true); } +static void bm_equal_vb_unaligned(benchmark::State& state) { bm_equal_vb(state, false); } + +// Test std::equal for vector::iterator +BENCHMARK(bm_equal_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_equal_vb_unaligned)->Range(8, 1 << 20); + BENCHMARK_MAIN(); diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp index c3ba3f89b4de3c..b37d788c80d3a6 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "test_iterators.h" #include "test_macros.h" @@ -123,6 +124,30 @@ class trivially_equality_comparable { #endif +template +TEST_CONSTEXPR_CXX20 void test_vector_bool() { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test equal() with aligned bytes + std::vector out = in; + assert(std::equal(in.begin(), in.end(), out.begin())); +#if TEST_STD_VER >= 14 + assert(std::equal(in.begin(), in.end(), out.begin(), out.end())); +#endif + } + + { // Test equal() with unaligned bytes + std::vector out(N + 8); + std::copy(in.begin(), in.end(), out.begin() + 4); + assert(std::equal(in.begin(), in.end(), out.begin() + 4)); +#if TEST_STD_VER >= 14 + assert(std::equal(in.begin(), in.end(), out.begin() + 4, out.end() - 4)); +#endif + } +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::cpp17_input_iterator_list(), TestIter2 >()); types::for_each( @@ -138,6 +163,16 @@ TEST_CONSTEXPR_CXX20 bool test() { TestIter2>{}); #endif + { // Test vector::iterator optimization + test_vector_bool<8>(); + test_vector_bool<19>(); + test_vector_bool<32>(); + test_vector_bool<49>(); + test_vector_bool<64>(); + test_vector_bool<199>(); + test_vector_bool<256>(); + } + return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/ranges.equal.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/ranges.equal.pass.cpp index f36cd2e0896552..4c1c29c72cab04 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/ranges.equal.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/ranges.equal.pass.cpp @@ -28,13 +28,17 @@ #include #include #include +#include #include "almost_satisfies_types.h" #include "test_iterators.h" +#include "test_macros.h" -template , - class Iter2 = Iter1, class Sent2 = sentinel_wrapper> -concept HasEqualIt = requires (Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { +template , + class Iter2 = Iter1, + class Sent2 = sentinel_wrapper> +concept HasEqualIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { std::ranges::equal(first1, last1, first2, last2); }; @@ -52,9 +56,7 @@ static_assert(!HasEqualIt); template -concept HasEqualR = requires (Range1 range1, Range2 range2) { - std::ranges::equal(range1, range2); -}; +concept HasEqualR = requires(Range1 range1, Range2 range2) { std::ranges::equal(range1, range2); }; static_assert(HasEqualR, UncheckedRange>); static_assert(!HasEqualR>); @@ -75,15 +77,15 @@ constexpr void test_iterators() { { int a[] = {1, 2, 3, 4}; int b[] = {1, 2, 3, 4}; - std::same_as decltype(auto) ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), - Iter2(b), Sent2(Iter2(b + 4))); + std::same_as decltype(auto) ret = + std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4))); assert(ret); } { - int a[] = {1, 2, 3, 4}; - int b[] = {1, 2, 3, 4}; - auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); - auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 4))); + int a[] = {1, 2, 3, 4}; + int b[] = {1, 2, 3, 4}; + auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); + auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 4))); std::same_as decltype(auto) ret = std::ranges::equal(range1, range2); assert(ret); } @@ -92,12 +94,12 @@ constexpr void test_iterators() { { // check that false is returned for non-equal ranges { int a[] = {1, 2, 3, 4}; - int b[] = {1, 2, 4, 4}; + int b[] = {1, 2, 4, 4}; assert(!std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4)))); } { - int a[] = {1, 2, 3, 4}; - int b[] = {1, 2, 4, 4}; + int a[] = {1, 2, 3, 4}; + int b[] = {1, 2, 4, 4}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 4))); assert(!std::ranges::equal(range1, range2)); @@ -106,95 +108,96 @@ constexpr void test_iterators() { { // check that the predicate is used (return true) { - int a[] = {1, 2, 3, 4}; - int b[] = {2, 3, 4, 5}; - auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4)), - [](int l, int r) { return l != r; }); + int a[] = {1, 2, 3, 4}; + int b[] = {2, 3, 4, 5}; + auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4)), [](int l, int r) { + return l != r; + }); assert(ret); } { - int a[] = {1, 2, 3, 4}; - int b[] = {2, 3, 4, 5}; + int a[] = {1, 2, 3, 4}; + int b[] = {2, 3, 4, 5}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 4))); - auto ret = std::ranges::equal(range1, range2, [](int l, int r) { return l != r; }); + auto ret = std::ranges::equal(range1, range2, [](int l, int r) { return l != r; }); assert(ret); } } { // check that the predicate is used (return false) { - int a[] = {1, 2, 3, 4}; - int b[] = {2, 3, 3, 5}; - auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4)), - [](int l, int r) { return l != r; }); + int a[] = {1, 2, 3, 4}; + int b[] = {2, 3, 3, 5}; + auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4)), [](int l, int r) { + return l != r; + }); assert(!ret); } { - int a[] = {1, 2, 3, 4}; - int b[] = {2, 3, 3, 5}; + int a[] = {1, 2, 3, 4}; + int b[] = {2, 3, 3, 5}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 4))); - auto ret = std::ranges::equal(range1, range2, [](int l, int r) { return l != r; }); + auto ret = std::ranges::equal(range1, range2, [](int l, int r) { return l != r; }); assert(!ret); } } { // check that the projections are used { - int a[] = {1, 2, 3, 4, 5}; - int b[] = {6, 10, 14, 18, 22}; - auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 5)), - Iter2(b), Sent2(Iter2(b + 5)), - {}, - [](int i) { return i * 4; }, - [](int i) { return i - 2; }); + int a[] = {1, 2, 3, 4, 5}; + int b[] = {6, 10, 14, 18, 22}; + auto ret = std::ranges::equal( + Iter1(a), + Sent1(Iter1(a + 5)), + Iter2(b), + Sent2(Iter2(b + 5)), + {}, + [](int i) { return i * 4; }, + [](int i) { return i - 2; }); assert(ret); } { - int a[] = {1, 2, 3, 4, 5}; - int b[] = {6, 10, 14, 18, 22}; + int a[] = {1, 2, 3, 4, 5}; + int b[] = {6, 10, 14, 18, 22}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 5))); - auto ret = std::ranges::equal(range1, - range2, - {}, - [](int i) { return i * 4; }, - [](int i) { return i - 2; }); + auto ret = std::ranges::equal(range1, range2, {}, [](int i) { return i * 4; }, [](int i) { return i - 2; }); assert(ret); } } { // check that different sized ranges work { - int a[] = {4, 3, 2, 1}; - int b[] = {4, 3, 2, 1, 5, 6, 7}; + int a[] = {4, 3, 2, 1}; + int b[] = {4, 3, 2, 1, 5, 6, 7}; auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 7))); assert(!ret); } { - int a[] = {4, 3, 2, 1}; - int b[] = {4, 3, 2, 1, 5, 6, 7}; + int a[] = {4, 3, 2, 1}; + int b[] = {4, 3, 2, 1, 5, 6, 7}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 7))); - auto ret = std::ranges::equal(range1, range2); + auto ret = std::ranges::equal(range1, range2); assert(!ret); } } { // check that two ranges with the same size but different values are different { - int a[] = {4, 6, 34, 76, 5}; - int b[] = {4, 6, 34, 67, 5}; + int a[] = {4, 6, 34, 76, 5}; + int b[] = {4, 6, 34, 67, 5}; auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 5)), Iter2(b), Sent2(Iter2(b + 5))); assert(!ret); } { - int a[] = {4, 6, 34, 76, 5}; - int b[] = {4, 6, 34, 67, 5}; + int a[] = {4, 6, 34, 76, 5}; + int b[] = {4, 6, 34, 67, 5}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 5))); - auto ret = std::ranges::equal(range1, range2); + auto ret = std::ranges::equal(range1, range2); assert(!ret); } } @@ -211,7 +214,7 @@ constexpr void test_iterators() { std::array b = {}; auto range1 = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data()))); auto range2 = std::ranges::subrange(Iter2(b.data()), Sent2(Iter2(b.data()))); - auto ret = std::ranges::equal(range1, range2); + auto ret = std::ranges::equal(range1, range2); assert(ret); } } @@ -219,39 +222,39 @@ constexpr void test_iterators() { { // check that it works with the first range empty { std::array a = {}; - int b[] = {1, 2}; + int b[] = {1, 2}; auto ret = std::ranges::equal(Iter1(a.data()), Sent1(Iter1(a.data())), Iter2(b), Sent2(Iter2(b + 2))); assert(!ret); } { std::array a = {}; - int b[] = {1, 2}; + int b[] = {1, 2}; auto range1 = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data()))); - auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 2))); - auto ret = std::ranges::equal(range1, range2); + auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 2))); + auto ret = std::ranges::equal(range1, range2); assert(!ret); } } { // check that it works with the second range empty { - int a[] = {1, 2}; + int a[] = {1, 2}; std::array b = {}; auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 2)), Iter2(b.data()), Sent2(Iter2(b.data()))); assert(!ret); } { - int a[] = {1, 2}; + int a[] = {1, 2}; std::array b = {}; - auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 2))); + auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 2))); auto range2 = std::ranges::subrange(Iter2(b.data()), Sent2(Iter2(b.data()))); - auto ret = std::ranges::equal(range1, range2); + auto ret = std::ranges::equal(range1, range2); assert(!ret); } } } -template +template constexpr void test_iterators2() { test_iterators, sentinel_wrapper>>(); test_iterators, sentinel_wrapper>>(); @@ -263,6 +266,22 @@ constexpr void test_iterators2() { test_iterators(); } +template +constexpr void test_vector_bool() { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + { // Test equal() with aligned bytes + std::vector out = in; + assert(std::ranges::equal(in, out)); + } + { // Test equal() with unaligned bytes + std::vector out(N + 8); + std::copy(in.begin(), in.end(), out.begin() + 4); + assert(std::ranges::equal(in.begin(), in.end(), out.begin() + 4, out.end() - 4)); + } +} + constexpr bool test() { test_iterators2, sentinel_wrapper>>(); test_iterators2, sentinel_wrapper>>(); @@ -281,40 +300,52 @@ constexpr bool test() { int i; }; { - S a[] = {7, 8, 9}; - S b[] = {7, 8, 9}; + S a[] = {7, 8, 9}; + S b[] = {7, 8, 9}; auto ret = std::ranges::equal(a, a + 3, b, b + 3, &S::equal, &S::identity, &S::i); assert(ret); } { - S a[] = {7, 8, 9}; - S b[] = {7, 8, 9}; + S a[] = {7, 8, 9}; + S b[] = {7, 8, 9}; auto ret = std::ranges::equal(a, b, &S::equal, &S::identity, &S::i); assert(ret); } } - { // check that the complexity requirements are met + { // check that the complexity requirements are met { // different size { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3, 4}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto ret = std::ranges::equal(a, a + 3, b, b + 4, pred, proj, proj); assert(!ret); assert(predCount == 0); assert(projCount == 0); } { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3, 4}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto ret = std::ranges::equal(a, b, pred, proj, proj); assert(!ret); assert(predCount == 0); @@ -324,27 +355,39 @@ constexpr bool test() { { // not a sized sentinel { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3, 4}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto ret = std::ranges::equal(a, sentinel_wrapper(a + 3), b, sentinel_wrapper(b + 4), pred, proj, proj); assert(!ret); assert(predCount <= 4); assert(projCount <= 7); } { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3, 4}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto range1 = std::ranges::subrange(a, sentinel_wrapper(a + 3)); auto range2 = std::ranges::subrange(b, sentinel_wrapper(b + 4)); - auto ret = std::ranges::equal(range1, range2, pred, proj, proj); + auto ret = std::ranges::equal(range1, range2, pred, proj, proj); assert(!ret); assert(predCount <= 4); assert(projCount <= 7); @@ -353,30 +396,52 @@ constexpr bool test() { { // same size { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto ret = std::ranges::equal(a, a + 3, b, b + 3, pred, proj, proj); assert(ret); assert(predCount == 3); assert(projCount == 6); } { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto ret = std::ranges::equal(a, b, pred, proj, proj); assert(ret); assert(predCount == 3); assert(projCount == 6); } } + + { // Test vector::iterator optimization + test_vector_bool<8>(); + test_vector_bool<19>(); + test_vector_bool<32>(); + test_vector_bool<49>(); + test_vector_bool<64>(); + test_vector_bool<199>(); + test_vector_bool<256>(); + } } return true; From libcxx-commits at lists.llvm.org Mon Feb 3 14:19:58 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Mon, 03 Feb 2025 14:19:58 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::equal for vector::iterator (PR #121084) In-Reply-To: Message-ID: <67a1410e.170a0220.f597b.0ce0@mx.google.com> https://github.com/winner245 edited https://github.com/llvm/llvm-project/pull/121084 From libcxx-commits at lists.llvm.org Mon Feb 3 14:27:16 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Mon, 03 Feb 2025 14:27:16 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::equal for vector::iterator (PR #121084) In-Reply-To: Message-ID: <67a142c4.050a0220.abc53.3cc2@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/121084 >From c47c0d82618435d48c2d21e05ab7685eea519d85 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Tue, 24 Dec 2024 18:24:39 -0500 Subject: [PATCH] Optimize ranges::equal for vector::iterator --- libcxx/docs/ReleaseNotes/21.rst | 2 + libcxx/include/__algorithm/equal.h | 160 +++++++++++ libcxx/include/__bit_reference | 135 +--------- libcxx/include/bitset | 1 + .../benchmarks/algorithms/equal.bench.cpp | 51 ++++ .../alg.nonmodifying/alg.equal/equal.pass.cpp | 35 +++ .../alg.equal/ranges.equal.pass.cpp | 251 +++++++++++------- 7 files changed, 418 insertions(+), 217 deletions(-) diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad39423..da5b541f9e20a22 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -46,6 +46,8 @@ Improvements and New Features - The ``std::ranges::{copy, copy_n, copy_backward}`` algorithms have been optimized for ``std::vector::iterator``\s, resulting in a performance improvement of up to 2000x. +- The ``std::ranges::equal`` algorithm has been optimized for ``std::vector::iterator``, resulting in a performance + improvement of up to 188x. Deprecations and Removals ------------------------- diff --git a/libcxx/include/__algorithm/equal.h b/libcxx/include/__algorithm/equal.h index a276bb9954c9bbc..c7f5ed2359ad79d 100644 --- a/libcxx/include/__algorithm/equal.h +++ b/libcxx/include/__algorithm/equal.h @@ -11,19 +11,27 @@ #define _LIBCPP___ALGORITHM_EQUAL_H #include <__algorithm/comp.h> +#include <__algorithm/min.h> #include <__algorithm/unwrap_iter.h> #include <__config> #include <__functional/identity.h> +#include <__fwd/bit_reference.h> #include <__iterator/distance.h> #include <__iterator/iterator_traits.h> +#include <__memory/pointer_traits.h> #include <__string/constexpr_c_functions.h> #include <__type_traits/desugars_to.h> #include <__type_traits/enable_if.h> #include <__type_traits/invoke.h> #include <__type_traits/is_equality_comparable.h> +#include <__type_traits/is_same.h> #include <__type_traits/is_volatile.h> #include <__utility/move.h> +#if _LIBCPP_STD_VER >= 20 +# include <__functional/ranges_operations.h> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif @@ -33,6 +41,132 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +template +[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_unaligned( + __bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { + using _It = __bit_iterator<_Cp, _IC1>; + using difference_type = typename _It::difference_type; + using __storage_type = typename _It::__storage_type; + + const int __bits_per_word = _It::__bits_per_word; + difference_type __n = __last1 - __first1; + if (__n > 0) { + // do first word + if (__first1.__ctz_ != 0) { + unsigned __clz_f = __bits_per_word - __first1.__ctz_; + difference_type __dn = std::min(static_cast(__clz_f), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __storage_type __b = *__first1.__seg_ & __m; + unsigned __clz_r = __bits_per_word - __first2.__ctz_; + __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r); + __m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn)); + if (__first2.__ctz_ > __first1.__ctz_) { + if ((*__first2.__seg_ & __m) != (__b << (__first2.__ctz_ - __first1.__ctz_))) + return false; + } else { + if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ - __first2.__ctz_))) + return false; + } + __first2.__seg_ += (__ddn + __first2.__ctz_) / __bits_per_word; + __first2.__ctz_ = static_cast((__ddn + __first2.__ctz_) % __bits_per_word); + __dn -= __ddn; + if (__dn > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __dn); + if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ + __ddn))) + return false; + __first2.__ctz_ = static_cast(__dn); + } + ++__first1.__seg_; + // __first1.__ctz_ = 0; + } + // __first1.__ctz_ == 0; + // do middle words + unsigned __clz_r = __bits_per_word - __first2.__ctz_; + __storage_type __m = ~__storage_type(0) << __first2.__ctz_; + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_) { + __storage_type __b = *__first1.__seg_; + if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_)) + return false; + ++__first2.__seg_; + if ((*__first2.__seg_ & ~__m) != (__b >> __clz_r)) + return false; + } + // do last word + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __b = *__first1.__seg_ & __m; + __storage_type __dn = std::min(__n, static_cast(__clz_r)); + __m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn)); + if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_)) + return false; + __first2.__seg_ += (__dn + __first2.__ctz_) / __bits_per_word; + __first2.__ctz_ = static_cast((__dn + __first2.__ctz_) % __bits_per_word); + __n -= __dn; + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + if ((*__first2.__seg_ & __m) != (__b >> __dn)) + return false; + } + } + } + return true; +} + +template +[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_aligned( + __bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { + using _It = __bit_iterator<_Cp, _IC1>; + using difference_type = typename _It::difference_type; + using __storage_type = typename _It::__storage_type; + + const int __bits_per_word = _It::__bits_per_word; + difference_type __n = __last1 - __first1; + if (__n > 0) { + // do first word + if (__first1.__ctz_ != 0) { + unsigned __clz = __bits_per_word - __first1.__ctz_; + difference_type __dn = std::min(static_cast(__clz), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz - __dn)); + if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m)) + return false; + ++__first2.__seg_; + ++__first1.__seg_; + // __first1.__ctz_ = 0; + // __first2.__ctz_ = 0; + } + // __first1.__ctz_ == 0; + // __first2.__ctz_ == 0; + // do middle words + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_, ++__first2.__seg_) + if (*__first2.__seg_ != *__first1.__seg_) + return false; + // do last word + if (__n > 0) { + __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m)) + return false; + } + } + return true; +} + +template ::value, int> = 0> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl( + __bit_iterator<_Cp, _IC1> __first1, + __bit_iterator<_Cp, _IC1> __last1, + __bit_iterator<_Cp, _IC2> __first2, + _BinaryPredicate) { + if (__first1.__ctz_ == __first2.__ctz_) + return std::__equal_aligned(__first1, __last1, __first2); + return std::__equal_unaligned(__first1, __last1, __first2); +} + template [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl( _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate& __pred) { @@ -94,6 +228,32 @@ __equal_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _Up*, _Pred&, _Proj1&, return std::__constexpr_memcmp_equal(__first1, __first2, __element_count(__last1 - __first1)); } +template ::value +# if _LIBCPP_STD_VER >= 20 + || is_same<_Pred, ranges::equal_to>::value +# endif + ) && + __desugars_to_v<__equal_tag, _Pred, bool, bool> && __is_identity<_Proj1>::value && + __is_identity<_Proj2>::value, + int> = 0> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_impl( + __bit_iterator<_Cp, _IC1> __first1, + __bit_iterator<_Cp, _IC1> __last1, + __bit_iterator<_Cp, _IC2> __first2, + __bit_iterator<_Cp, _IC2>, + _Pred&, + _Proj1&, + _Proj2&) { + __equal_to __pred; + return std::__equal_iter_impl(__first1, __last1, __first2, __pred); +} + template [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool equal(_InputIterator1 __first1, diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c398059..de518b7cf5af8f5 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -10,9 +10,11 @@ #ifndef _LIBCPP___BIT_REFERENCE #define _LIBCPP___BIT_REFERENCE +#include <__algorithm/comp.h> #include <__algorithm/copy.h> #include <__algorithm/copy_backward.h> #include <__algorithm/copy_n.h> +#include <__algorithm/equal.h> #include <__algorithm/min.h> #include <__bit/countr.h> #include <__compare/ordering.h> @@ -24,7 +26,9 @@ #include <__memory/construct_at.h> #include <__memory/pointer_traits.h> #include <__type_traits/conditional.h> +#include <__type_traits/enable_if.h> #include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_same.h> #include <__type_traits/void_t.h> #include <__utility/pair.h> #include <__utility/swap.h> @@ -420,127 +424,6 @@ rotate(__bit_iterator<_Cp, false> __first, __bit_iterator<_Cp, false> __middle, return __r; } -// equal - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_unaligned( - __bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { - using _It = __bit_iterator<_Cp, _IC1>; - using difference_type = typename _It::difference_type; - using __storage_type = typename _It::__storage_type; - - const int __bits_per_word = _It::__bits_per_word; - difference_type __n = __last1 - __first1; - if (__n > 0) { - // do first word - if (__first1.__ctz_ != 0) { - unsigned __clz_f = __bits_per_word - __first1.__ctz_; - difference_type __dn = std::min(static_cast(__clz_f), __n); - __n -= __dn; - __storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - __storage_type __b = *__first1.__seg_ & __m; - unsigned __clz_r = __bits_per_word - __first2.__ctz_; - __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r); - __m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn)); - if (__first2.__ctz_ > __first1.__ctz_) { - if ((*__first2.__seg_ & __m) != (__b << (__first2.__ctz_ - __first1.__ctz_))) - return false; - } else { - if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ - __first2.__ctz_))) - return false; - } - __first2.__seg_ += (__ddn + __first2.__ctz_) / __bits_per_word; - __first2.__ctz_ = static_cast((__ddn + __first2.__ctz_) % __bits_per_word); - __dn -= __ddn; - if (__dn > 0) { - __m = ~__storage_type(0) >> (__bits_per_word - __dn); - if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ + __ddn))) - return false; - __first2.__ctz_ = static_cast(__dn); - } - ++__first1.__seg_; - // __first1.__ctz_ = 0; - } - // __first1.__ctz_ == 0; - // do middle words - unsigned __clz_r = __bits_per_word - __first2.__ctz_; - __storage_type __m = ~__storage_type(0) << __first2.__ctz_; - for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_) { - __storage_type __b = *__first1.__seg_; - if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_)) - return false; - ++__first2.__seg_; - if ((*__first2.__seg_ & ~__m) != (__b >> __clz_r)) - return false; - } - // do last word - if (__n > 0) { - __m = ~__storage_type(0) >> (__bits_per_word - __n); - __storage_type __b = *__first1.__seg_ & __m; - __storage_type __dn = std::min(__n, static_cast(__clz_r)); - __m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn)); - if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_)) - return false; - __first2.__seg_ += (__dn + __first2.__ctz_) / __bits_per_word; - __first2.__ctz_ = static_cast((__dn + __first2.__ctz_) % __bits_per_word); - __n -= __dn; - if (__n > 0) { - __m = ~__storage_type(0) >> (__bits_per_word - __n); - if ((*__first2.__seg_ & __m) != (__b >> __dn)) - return false; - } - } - } - return true; -} - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_aligned( - __bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { - using _It = __bit_iterator<_Cp, _IC1>; - using difference_type = typename _It::difference_type; - using __storage_type = typename _It::__storage_type; - - const int __bits_per_word = _It::__bits_per_word; - difference_type __n = __last1 - __first1; - if (__n > 0) { - // do first word - if (__first1.__ctz_ != 0) { - unsigned __clz = __bits_per_word - __first1.__ctz_; - difference_type __dn = std::min(static_cast(__clz), __n); - __n -= __dn; - __storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz - __dn)); - if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m)) - return false; - ++__first2.__seg_; - ++__first1.__seg_; - // __first1.__ctz_ = 0; - // __first2.__ctz_ = 0; - } - // __first1.__ctz_ == 0; - // __first2.__ctz_ == 0; - // do middle words - for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_, ++__first2.__seg_) - if (*__first2.__seg_ != *__first1.__seg_) - return false; - // do last word - if (__n > 0) { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m)) - return false; - } - } - return true; -} - -template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool -equal(__bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { - if (__first1.__ctz_ == __first2.__ctz_) - return std::__equal_aligned(__first1, __last1, __first2); - return std::__equal_unaligned(__first1, __last1, __first2); -} - template class __bit_iterator { public: @@ -769,9 +652,13 @@ private: template _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool __equal_unaligned(__bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>); - template - _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool - equal(__bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>); + template ::value, int> > + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool __equal_iter_impl( + __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>, _BinaryPredicate); template _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, _IC> __find_bool(__bit_iterator<_Dp, _IC>, typename __size_difference_type_traits<_Dp>::size_type); diff --git a/libcxx/include/bitset b/libcxx/include/bitset index a20842985b3d59d..afc44daa9ed380d 100644 --- a/libcxx/include/bitset +++ b/libcxx/include/bitset @@ -132,6 +132,7 @@ template struct hash>; # include <__algorithm/copy.h> # include <__algorithm/copy_backward.h> # include <__algorithm/count.h> +# include <__algorithm/equal.h> # include <__algorithm/fill.h> # include <__algorithm/fill_n.h> # include <__algorithm/find.h> diff --git a/libcxx/test/benchmarks/algorithms/equal.bench.cpp b/libcxx/test/benchmarks/algorithms/equal.bench.cpp index 2dc11585c15c7f7..328b39608607ede 100644 --- a/libcxx/test/benchmarks/algorithms/equal.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/equal.bench.cpp @@ -45,4 +45,55 @@ static void bm_ranges_equal(benchmark::State& state) { } BENCHMARK(bm_ranges_equal)->DenseRange(1, 8)->Range(16, 1 << 20); +static void bm_ranges_equal_vb_aligned(benchmark::State& state) { + auto n = state.range(); + std::vector vec1(n, true); + std::vector vec2(n, true); + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::equal(vec1, vec2)); + benchmark::DoNotOptimize(&vec1); + benchmark::DoNotOptimize(&vec2); + } +} + +static void bm_ranges_equal_vb_unaligned(benchmark::State& state) { + auto n = state.range(); + std::vector vec1(n, true); + std::vector vec2(n + 8, true); + auto beg1 = std::ranges::begin(vec1); + auto end1 = std::ranges::end(vec1); + auto beg2 = std::ranges::begin(vec2) + 4; + auto end2 = std::ranges::end(vec2) - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::equal(beg1, end1, beg2, end2)); + benchmark::DoNotOptimize(&vec1); + benchmark::DoNotOptimize(&vec2); + } +} + +// Test std::ranges::equal for vector::iterator +BENCHMARK(bm_ranges_equal_vb_aligned)->RangeMultiplier(4)->Range(8, 1 << 20); +BENCHMARK(bm_ranges_equal_vb_unaligned)->Range(8, 1 << 20); + +static void bm_equal_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector vec1(n, true); + std::vector vec2(aligned ? n : n + 8, true); + auto beg1 = vec1.begin(); + auto end1 = vec1.end(); + auto beg2 = aligned ? vec2.begin() : vec2.begin() + 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::equal(beg1, end1, beg2)); + benchmark::DoNotOptimize(&vec1); + benchmark::DoNotOptimize(&vec2); + } +} + +static void bm_equal_vb_aligned(benchmark::State& state) { bm_equal_vb(state, true); } +static void bm_equal_vb_unaligned(benchmark::State& state) { bm_equal_vb(state, false); } + +// Test std::equal for vector::iterator +BENCHMARK(bm_equal_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_equal_vb_unaligned)->Range(8, 1 << 20); + BENCHMARK_MAIN(); diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp index c3ba3f89b4de3c5..b37d788c80d3a6d 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "test_iterators.h" #include "test_macros.h" @@ -123,6 +124,30 @@ class trivially_equality_comparable { #endif +template +TEST_CONSTEXPR_CXX20 void test_vector_bool() { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test equal() with aligned bytes + std::vector out = in; + assert(std::equal(in.begin(), in.end(), out.begin())); +#if TEST_STD_VER >= 14 + assert(std::equal(in.begin(), in.end(), out.begin(), out.end())); +#endif + } + + { // Test equal() with unaligned bytes + std::vector out(N + 8); + std::copy(in.begin(), in.end(), out.begin() + 4); + assert(std::equal(in.begin(), in.end(), out.begin() + 4)); +#if TEST_STD_VER >= 14 + assert(std::equal(in.begin(), in.end(), out.begin() + 4, out.end() - 4)); +#endif + } +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::cpp17_input_iterator_list(), TestIter2 >()); types::for_each( @@ -138,6 +163,16 @@ TEST_CONSTEXPR_CXX20 bool test() { TestIter2>{}); #endif + { // Test vector::iterator optimization + test_vector_bool<8>(); + test_vector_bool<19>(); + test_vector_bool<32>(); + test_vector_bool<49>(); + test_vector_bool<64>(); + test_vector_bool<199>(); + test_vector_bool<256>(); + } + return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/ranges.equal.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/ranges.equal.pass.cpp index f36cd2e08965529..4c1c29c72cab044 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/ranges.equal.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/ranges.equal.pass.cpp @@ -28,13 +28,17 @@ #include #include #include +#include #include "almost_satisfies_types.h" #include "test_iterators.h" +#include "test_macros.h" -template , - class Iter2 = Iter1, class Sent2 = sentinel_wrapper> -concept HasEqualIt = requires (Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { +template , + class Iter2 = Iter1, + class Sent2 = sentinel_wrapper> +concept HasEqualIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { std::ranges::equal(first1, last1, first2, last2); }; @@ -52,9 +56,7 @@ static_assert(!HasEqualIt); template -concept HasEqualR = requires (Range1 range1, Range2 range2) { - std::ranges::equal(range1, range2); -}; +concept HasEqualR = requires(Range1 range1, Range2 range2) { std::ranges::equal(range1, range2); }; static_assert(HasEqualR, UncheckedRange>); static_assert(!HasEqualR>); @@ -75,15 +77,15 @@ constexpr void test_iterators() { { int a[] = {1, 2, 3, 4}; int b[] = {1, 2, 3, 4}; - std::same_as decltype(auto) ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), - Iter2(b), Sent2(Iter2(b + 4))); + std::same_as decltype(auto) ret = + std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4))); assert(ret); } { - int a[] = {1, 2, 3, 4}; - int b[] = {1, 2, 3, 4}; - auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); - auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 4))); + int a[] = {1, 2, 3, 4}; + int b[] = {1, 2, 3, 4}; + auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); + auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 4))); std::same_as decltype(auto) ret = std::ranges::equal(range1, range2); assert(ret); } @@ -92,12 +94,12 @@ constexpr void test_iterators() { { // check that false is returned for non-equal ranges { int a[] = {1, 2, 3, 4}; - int b[] = {1, 2, 4, 4}; + int b[] = {1, 2, 4, 4}; assert(!std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4)))); } { - int a[] = {1, 2, 3, 4}; - int b[] = {1, 2, 4, 4}; + int a[] = {1, 2, 3, 4}; + int b[] = {1, 2, 4, 4}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 4))); assert(!std::ranges::equal(range1, range2)); @@ -106,95 +108,96 @@ constexpr void test_iterators() { { // check that the predicate is used (return true) { - int a[] = {1, 2, 3, 4}; - int b[] = {2, 3, 4, 5}; - auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4)), - [](int l, int r) { return l != r; }); + int a[] = {1, 2, 3, 4}; + int b[] = {2, 3, 4, 5}; + auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4)), [](int l, int r) { + return l != r; + }); assert(ret); } { - int a[] = {1, 2, 3, 4}; - int b[] = {2, 3, 4, 5}; + int a[] = {1, 2, 3, 4}; + int b[] = {2, 3, 4, 5}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 4))); - auto ret = std::ranges::equal(range1, range2, [](int l, int r) { return l != r; }); + auto ret = std::ranges::equal(range1, range2, [](int l, int r) { return l != r; }); assert(ret); } } { // check that the predicate is used (return false) { - int a[] = {1, 2, 3, 4}; - int b[] = {2, 3, 3, 5}; - auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4)), - [](int l, int r) { return l != r; }); + int a[] = {1, 2, 3, 4}; + int b[] = {2, 3, 3, 5}; + auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4)), [](int l, int r) { + return l != r; + }); assert(!ret); } { - int a[] = {1, 2, 3, 4}; - int b[] = {2, 3, 3, 5}; + int a[] = {1, 2, 3, 4}; + int b[] = {2, 3, 3, 5}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 4))); - auto ret = std::ranges::equal(range1, range2, [](int l, int r) { return l != r; }); + auto ret = std::ranges::equal(range1, range2, [](int l, int r) { return l != r; }); assert(!ret); } } { // check that the projections are used { - int a[] = {1, 2, 3, 4, 5}; - int b[] = {6, 10, 14, 18, 22}; - auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 5)), - Iter2(b), Sent2(Iter2(b + 5)), - {}, - [](int i) { return i * 4; }, - [](int i) { return i - 2; }); + int a[] = {1, 2, 3, 4, 5}; + int b[] = {6, 10, 14, 18, 22}; + auto ret = std::ranges::equal( + Iter1(a), + Sent1(Iter1(a + 5)), + Iter2(b), + Sent2(Iter2(b + 5)), + {}, + [](int i) { return i * 4; }, + [](int i) { return i - 2; }); assert(ret); } { - int a[] = {1, 2, 3, 4, 5}; - int b[] = {6, 10, 14, 18, 22}; + int a[] = {1, 2, 3, 4, 5}; + int b[] = {6, 10, 14, 18, 22}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 5))); - auto ret = std::ranges::equal(range1, - range2, - {}, - [](int i) { return i * 4; }, - [](int i) { return i - 2; }); + auto ret = std::ranges::equal(range1, range2, {}, [](int i) { return i * 4; }, [](int i) { return i - 2; }); assert(ret); } } { // check that different sized ranges work { - int a[] = {4, 3, 2, 1}; - int b[] = {4, 3, 2, 1, 5, 6, 7}; + int a[] = {4, 3, 2, 1}; + int b[] = {4, 3, 2, 1, 5, 6, 7}; auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 7))); assert(!ret); } { - int a[] = {4, 3, 2, 1}; - int b[] = {4, 3, 2, 1, 5, 6, 7}; + int a[] = {4, 3, 2, 1}; + int b[] = {4, 3, 2, 1, 5, 6, 7}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 7))); - auto ret = std::ranges::equal(range1, range2); + auto ret = std::ranges::equal(range1, range2); assert(!ret); } } { // check that two ranges with the same size but different values are different { - int a[] = {4, 6, 34, 76, 5}; - int b[] = {4, 6, 34, 67, 5}; + int a[] = {4, 6, 34, 76, 5}; + int b[] = {4, 6, 34, 67, 5}; auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 5)), Iter2(b), Sent2(Iter2(b + 5))); assert(!ret); } { - int a[] = {4, 6, 34, 76, 5}; - int b[] = {4, 6, 34, 67, 5}; + int a[] = {4, 6, 34, 76, 5}; + int b[] = {4, 6, 34, 67, 5}; auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 5))); - auto ret = std::ranges::equal(range1, range2); + auto ret = std::ranges::equal(range1, range2); assert(!ret); } } @@ -211,7 +214,7 @@ constexpr void test_iterators() { std::array b = {}; auto range1 = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data()))); auto range2 = std::ranges::subrange(Iter2(b.data()), Sent2(Iter2(b.data()))); - auto ret = std::ranges::equal(range1, range2); + auto ret = std::ranges::equal(range1, range2); assert(ret); } } @@ -219,39 +222,39 @@ constexpr void test_iterators() { { // check that it works with the first range empty { std::array a = {}; - int b[] = {1, 2}; + int b[] = {1, 2}; auto ret = std::ranges::equal(Iter1(a.data()), Sent1(Iter1(a.data())), Iter2(b), Sent2(Iter2(b + 2))); assert(!ret); } { std::array a = {}; - int b[] = {1, 2}; + int b[] = {1, 2}; auto range1 = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data()))); - auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 2))); - auto ret = std::ranges::equal(range1, range2); + auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 2))); + auto ret = std::ranges::equal(range1, range2); assert(!ret); } } { // check that it works with the second range empty { - int a[] = {1, 2}; + int a[] = {1, 2}; std::array b = {}; auto ret = std::ranges::equal(Iter1(a), Sent1(Iter1(a + 2)), Iter2(b.data()), Sent2(Iter2(b.data()))); assert(!ret); } { - int a[] = {1, 2}; + int a[] = {1, 2}; std::array b = {}; - auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 2))); + auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 2))); auto range2 = std::ranges::subrange(Iter2(b.data()), Sent2(Iter2(b.data()))); - auto ret = std::ranges::equal(range1, range2); + auto ret = std::ranges::equal(range1, range2); assert(!ret); } } } -template +template constexpr void test_iterators2() { test_iterators, sentinel_wrapper>>(); test_iterators, sentinel_wrapper>>(); @@ -263,6 +266,22 @@ constexpr void test_iterators2() { test_iterators(); } +template +constexpr void test_vector_bool() { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + { // Test equal() with aligned bytes + std::vector out = in; + assert(std::ranges::equal(in, out)); + } + { // Test equal() with unaligned bytes + std::vector out(N + 8); + std::copy(in.begin(), in.end(), out.begin() + 4); + assert(std::ranges::equal(in.begin(), in.end(), out.begin() + 4, out.end() - 4)); + } +} + constexpr bool test() { test_iterators2, sentinel_wrapper>>(); test_iterators2, sentinel_wrapper>>(); @@ -281,40 +300,52 @@ constexpr bool test() { int i; }; { - S a[] = {7, 8, 9}; - S b[] = {7, 8, 9}; + S a[] = {7, 8, 9}; + S b[] = {7, 8, 9}; auto ret = std::ranges::equal(a, a + 3, b, b + 3, &S::equal, &S::identity, &S::i); assert(ret); } { - S a[] = {7, 8, 9}; - S b[] = {7, 8, 9}; + S a[] = {7, 8, 9}; + S b[] = {7, 8, 9}; auto ret = std::ranges::equal(a, b, &S::equal, &S::identity, &S::i); assert(ret); } } - { // check that the complexity requirements are met + { // check that the complexity requirements are met { // different size { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3, 4}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto ret = std::ranges::equal(a, a + 3, b, b + 4, pred, proj, proj); assert(!ret); assert(predCount == 0); assert(projCount == 0); } { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3, 4}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto ret = std::ranges::equal(a, b, pred, proj, proj); assert(!ret); assert(predCount == 0); @@ -324,27 +355,39 @@ constexpr bool test() { { // not a sized sentinel { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3, 4}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto ret = std::ranges::equal(a, sentinel_wrapper(a + 3), b, sentinel_wrapper(b + 4), pred, proj, proj); assert(!ret); assert(predCount <= 4); assert(projCount <= 7); } { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3, 4}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto range1 = std::ranges::subrange(a, sentinel_wrapper(a + 3)); auto range2 = std::ranges::subrange(b, sentinel_wrapper(b + 4)); - auto ret = std::ranges::equal(range1, range2, pred, proj, proj); + auto ret = std::ranges::equal(range1, range2, pred, proj, proj); assert(!ret); assert(predCount <= 4); assert(projCount <= 7); @@ -353,30 +396,52 @@ constexpr bool test() { { // same size { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto ret = std::ranges::equal(a, a + 3, b, b + 3, pred, proj, proj); assert(ret); assert(predCount == 3); assert(projCount == 6); } { - int a[] = {1, 2, 3}; - int b[] = {1, 2, 3}; + int a[] = {1, 2, 3}; + int b[] = {1, 2, 3}; int predCount = 0; int projCount = 0; - auto pred = [&](int l, int r) { ++predCount; return l == r; }; - auto proj = [&](int i) { ++projCount; return i; }; + auto pred = [&](int l, int r) { + ++predCount; + return l == r; + }; + auto proj = [&](int i) { + ++projCount; + return i; + }; auto ret = std::ranges::equal(a, b, pred, proj, proj); assert(ret); assert(predCount == 3); assert(projCount == 6); } } + + { // Test vector::iterator optimization + test_vector_bool<8>(); + test_vector_bool<19>(); + test_vector_bool<32>(); + test_vector_bool<49>(); + test_vector_bool<64>(); + test_vector_bool<199>(); + test_vector_bool<256>(); + } } return true; From libcxx-commits at lists.llvm.org Mon Feb 3 15:29:40 2025 From: libcxx-commits at lists.llvm.org (Konstantin Varlamov via libcxx-commits) Date: Mon, 03 Feb 2025 15:29:40 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a15164.170a0220.5ddd3.73a7@mx.google.com> var-const wrote: @philnik777 > This just pushes the diagnostic to be a linker error instead most likely, which isn't great. What would the linker error look like? https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 15:36:36 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 15:36:36 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a15304.630a0220.d742a.2da6@mx.google.com> philnik777 wrote: > @philnik777 > > > This just pushes the diagnostic to be a linker error instead most likely, which isn't great. > > What would the linker error look like? Probably something along the lines of "undefined symbol x referenced in y". Or, if it's linked dynamically, at program startup something similar. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 15:39:08 2025 From: libcxx-commits at lists.llvm.org (Konstantin Varlamov via libcxx-commits) Date: Mon, 03 Feb 2025 15:39:08 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a1539c.170a0220.3b0331.0d22@mx.google.com> var-const wrote: @philnik777 I was unsuccessful trying to get one on Godbolt. The compiler simply ignores the user-provided sized overload when resolving a `delete` expression if sized allocations are not available -- but it's very possible I'm not trying the right combination of the compiler / flags / etc. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 15:41:30 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 15:41:30 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a1542a.170a0220.2336d2.1235@mx.google.com> philnik777 wrote: > @philnik777 I was unsuccessful trying to get one on Godbolt. The compiler simply ignores the user-provided sized overload when resolving a `delete` expression if sized allocations are not available -- but it's very possible I'm not trying the right combination of the compiler / flags / etc. Yes, that's the point of the flag. You have to explicitly use the sized deallocation overload with this patch, but I don't see when you'd want to be able to manually call the function but not tell the compiler that it exists. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 15:41:46 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Mon, 03 Feb 2025 15:41:46 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::swap_ranges for vector::iterator (PR #121150) In-Reply-To: Message-ID: <67a1543a.170a0220.349833.1802@mx.google.com> https://github.com/winner245 edited https://github.com/llvm/llvm-project/pull/121150 From libcxx-commits at lists.llvm.org Mon Feb 3 15:44:37 2025 From: libcxx-commits at lists.llvm.org (Konstantin Varlamov via libcxx-commits) Date: Mon, 03 Feb 2025 15:44:37 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a154e5.170a0220.2c23f6.2270@mx.google.com> var-const wrote: > Yes, that's the point of the flag. You have to explicitly use the sized deallocation overload with this patch, but I don't see when you'd want to be able to manually call the function but not tell the compiler that it exists Right, but that's a separate issue -- I'd like to first make sure this patch doesn't result in linker errors (in some contexts) before discussing whether we should do anything in the library to prevent silently ignoring user's overload. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 15:45:40 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 15:45:40 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a15524.170a0220.351dfb.02ed@mx.google.com> philnik777 wrote: Thinking about it, we could add deleted versions of sized deallocation and tell the user that they should enable `-fsized-deallocation` if they provide their own overloads. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 15:48:02 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 15:48:02 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a155b2.170a0220.3b0331.0d8d@mx.google.com> philnik777 wrote: > > Yes, that's the point of the flag. You have to explicitly use the sized deallocation overload with this patch, but I don't see when you'd want to be able to manually call the function but not tell the compiler that it exists > > Right, but that's a separate issue -- I'd like to first make sure this patch doesn't result in linker errors (in some contexts) before discussing whether we should do anything in the library to prevent silently ignoring user's overload. I don't think that's a separate issue. AFAICT this is the only scenario this patch allows. If you thought I meant this could lead to linker issues for code that doesn't manually call the sized overloads, I'm sorry for the confusion. I didn't mean that. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Mon Feb 3 16:13:13 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Mon, 03 Feb 2025 16:13:13 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Support `constexpr` for `std::stable_sort` in radix sort branch (PR #125284) Message-ID: <67a15b99.050a0220.2ed62c.3e7f@mx.google.com> =?utf-8?b?0JTQvNC40YLRgNC40Lkg0JjQtw==?=, =?utf-8?b?0JTQvNC40YLRgNC40Lkg0JjQtw==?= Message-ID: In-Reply-To: philnik777 wrote: @izvolov Did you forget to upload the update? https://github.com/llvm/llvm-project/pull/125284 From libcxx-commits at lists.llvm.org Mon Feb 3 19:38:34 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Mon, 03 Feb 2025 19:38:34 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize ranges::swap_ranges for vector::iterator (PR #121150) In-Reply-To: Message-ID: <67a18bba.050a0220.3a7621.440c@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/121150 >From 61aaca6f5576dc7de733aaaa3b4d934f19d1f4b5 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Wed, 25 Dec 2024 16:06:35 -0500 Subject: [PATCH] Optimize ranges::swap_ranges for vector::iterator --- libcxx/docs/ReleaseNotes/21.rst | 2 + libcxx/include/__algorithm/swap_ranges.h | 162 ++++++++++++ libcxx/include/__bit_reference | 157 +---------- .../algorithms/swap_ranges.bench.cpp | 66 +++++ .../alg.swap/iter_swap.pass.cpp | 26 +- .../alg.swap/ranges.swap_ranges.pass.cpp | 58 +++-- .../alg.swap/swap_ranges.pass.cpp | 246 ++++++++++-------- 7 files changed, 421 insertions(+), 296 deletions(-) create mode 100644 libcxx/test/benchmarks/algorithms/swap_ranges.bench.cpp diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad39423..5d3e6a797ac551c 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -46,6 +46,8 @@ Improvements and New Features - The ``std::ranges::{copy, copy_n, copy_backward}`` algorithms have been optimized for ``std::vector::iterator``\s, resulting in a performance improvement of up to 2000x. +- The ``std::ranges::swap_ranges`` algorithm has been optimized for ``std::vector::iterator``, resulting in a + performance improvement of up to 611x. Deprecations and Removals ------------------------- diff --git a/libcxx/include/__algorithm/swap_ranges.h b/libcxx/include/__algorithm/swap_ranges.h index 54b453b72360e0b..2731d4feaa63d4d 100644 --- a/libcxx/include/__algorithm/swap_ranges.h +++ b/libcxx/include/__algorithm/swap_ranges.h @@ -10,9 +10,12 @@ #define _LIBCPP___ALGORITHM_SWAP_RANGES_H #include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> #include <__config> +#include <__fwd/bit_reference.h> #include <__utility/move.h> #include <__utility/pair.h> +#include <__utility/swap.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -23,6 +26,165 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cr, false> __swap_ranges_aligned( + __bit_iterator<_Cl, false> __first, __bit_iterator<_Cl, false> __last, __bit_iterator<_Cr, false> __result) { + using _I1 = __bit_iterator<_Cl, false>; + using difference_type = typename _I1::difference_type; + using __storage_type = typename _I1::__storage_type; + + const int __bits_per_word = _I1::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__first.__ctz_ != 0) { + unsigned __clz = __bits_per_word - __first.__ctz_; + difference_type __dn = std::min(static_cast(__clz), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz - __dn)); + __storage_type __b1 = *__first.__seg_ & __m; + *__first.__seg_ &= ~__m; + __storage_type __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b1; + *__first.__seg_ |= __b2; + __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast((__dn + __result.__ctz_) % __bits_per_word); + ++__first.__seg_; + // __first.__ctz_ = 0; + } + // __first.__ctz_ == 0; + // do middle words + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_, ++__result.__seg_) + swap(*__first.__seg_, *__result.__seg_); + // do last word + if (__n > 0) { + __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __b1 = *__first.__seg_ & __m; + *__first.__seg_ &= ~__m; + __storage_type __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b1; + *__first.__seg_ |= __b2; + __result.__ctz_ = static_cast(__n); + } + } + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cr, false> __swap_ranges_unaligned( + __bit_iterator<_Cl, false> __first, __bit_iterator<_Cl, false> __last, __bit_iterator<_Cr, false> __result) { + using _I1 = __bit_iterator<_Cl, false>; + using difference_type = typename _I1::difference_type; + using __storage_type = typename _I1::__storage_type; + + const int __bits_per_word = _I1::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__first.__ctz_ != 0) { + unsigned __clz_f = __bits_per_word - __first.__ctz_; + difference_type __dn = std::min(static_cast(__clz_f), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __storage_type __b1 = *__first.__seg_ & __m; + *__first.__seg_ &= ~__m; + unsigned __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r); + __m = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn)); + __storage_type __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + if (__result.__ctz_ > __first.__ctz_) { + unsigned __s = __result.__ctz_ - __first.__ctz_; + *__result.__seg_ |= __b1 << __s; + *__first.__seg_ |= __b2 >> __s; + } else { + unsigned __s = __first.__ctz_ - __result.__ctz_; + *__result.__seg_ |= __b1 >> __s; + *__first.__seg_ |= __b2 << __s; + } + __result.__seg_ += (__ddn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast((__ddn + __result.__ctz_) % __bits_per_word); + __dn -= __ddn; + if (__dn > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __dn); + __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + unsigned __s = __first.__ctz_ + __ddn; + *__result.__seg_ |= __b1 >> __s; + *__first.__seg_ |= __b2 << __s; + __result.__ctz_ = static_cast(__dn); + } + ++__first.__seg_; + // __first.__ctz_ = 0; + } + // __first.__ctz_ == 0; + // do middle words + __storage_type __m = ~__storage_type(0) << __result.__ctz_; + unsigned __clz_r = __bits_per_word - __result.__ctz_; + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_) { + __storage_type __b1 = *__first.__seg_; + __storage_type __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b1 << __result.__ctz_; + *__first.__seg_ = __b2 >> __result.__ctz_; + ++__result.__seg_; + __b2 = *__result.__seg_ & ~__m; + *__result.__seg_ &= __m; + *__result.__seg_ |= __b1 >> __clz_r; + *__first.__seg_ |= __b2 << __clz_r; + } + // do last word + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __b1 = *__first.__seg_ & __m; + *__first.__seg_ &= ~__m; + __storage_type __dn = std::min<__storage_type>(__n, __clz_r); + __m = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn)); + __storage_type __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b1 << __result.__ctz_; + *__first.__seg_ |= __b2 >> __result.__ctz_; + __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast((__dn + __result.__ctz_) % __bits_per_word); + __n -= __dn; + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b1 >> __dn; + *__first.__seg_ |= __b2 << __dn; + __result.__ctz_ = static_cast(__n); + } + } + } + return __result; +} + +// 2+1 iterators: size2 >= size1; used by std::swap_ranges. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cl, false>, __bit_iterator<_Cr, false> > +__swap_ranges(__bit_iterator<_Cl, false> __first1, + __bit_iterator<_Cl, false> __last1, + __bit_iterator<_Cr, false> __first2) { + if (__first1.__ctz_ == __first2.__ctz_) + return std::make_pair(__last1, std::__swap_ranges_aligned(__first1, __last1, __first2)); + return std::make_pair(__last1, std::__swap_ranges_unaligned(__first1, __last1, __first2)); +} + +// 2+2 iterators: used by std::ranges::swap_ranges. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cl, false>, __bit_iterator<_Cr, false> > +__swap_ranges(__bit_iterator<_Cl, false> __first1, + __bit_iterator<_Cl, false> __last1, + __bit_iterator<_Cr, false> __first2, + __bit_iterator<_Cr, false> __last2) { + if (__last1 - __first1 < __last2 - __first2) + return std::make_pair(__last1, std::__swap_ranges<_AlgPolicy>(__first1, __last1, __first2).second); + return std::make_pair(std::__swap_ranges<_AlgPolicy>(__first2, __last2, __first1).second, __last2); +} + // 2+2 iterators: the shorter size will be used. template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator1, _ForwardIterator2> diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c398059..15c38a564a388f0 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -14,6 +14,7 @@ #include <__algorithm/copy_backward.h> #include <__algorithm/copy_n.h> #include <__algorithm/min.h> +#include <__algorithm/swap_ranges.h> #include <__bit/countr.h> #include <__compare/ordering.h> #include <__config> @@ -202,152 +203,6 @@ inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> move_backward( return std::copy_backward(__first, __last, __result); } -// swap_ranges - -template -_LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cr, false> __swap_ranges_aligned( - __bit_iterator<_Cl, false> __first, __bit_iterator<_Cl, false> __last, __bit_iterator<_Cr, false> __result) { - using _I1 = __bit_iterator<_Cl, false>; - using difference_type = typename _I1::difference_type; - using __storage_type = typename _I1::__storage_type; - - const int __bits_per_word = _I1::__bits_per_word; - difference_type __n = __last - __first; - if (__n > 0) { - // do first word - if (__first.__ctz_ != 0) { - unsigned __clz = __bits_per_word - __first.__ctz_; - difference_type __dn = std::min(static_cast(__clz), __n); - __n -= __dn; - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz - __dn)); - __storage_type __b1 = *__first.__seg_ & __m; - *__first.__seg_ &= ~__m; - __storage_type __b2 = *__result.__seg_ & __m; - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b1; - *__first.__seg_ |= __b2; - __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; - __result.__ctz_ = static_cast((__dn + __result.__ctz_) % __bits_per_word); - ++__first.__seg_; - // __first.__ctz_ = 0; - } - // __first.__ctz_ == 0; - // do middle words - for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_, ++__result.__seg_) - swap(*__first.__seg_, *__result.__seg_); - // do last word - if (__n > 0) { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - __storage_type __b1 = *__first.__seg_ & __m; - *__first.__seg_ &= ~__m; - __storage_type __b2 = *__result.__seg_ & __m; - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b1; - *__first.__seg_ |= __b2; - __result.__ctz_ = static_cast(__n); - } - } - return __result; -} - -template -_LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cr, false> __swap_ranges_unaligned( - __bit_iterator<_Cl, false> __first, __bit_iterator<_Cl, false> __last, __bit_iterator<_Cr, false> __result) { - using _I1 = __bit_iterator<_Cl, false>; - using difference_type = typename _I1::difference_type; - using __storage_type = typename _I1::__storage_type; - - const int __bits_per_word = _I1::__bits_per_word; - difference_type __n = __last - __first; - if (__n > 0) { - // do first word - if (__first.__ctz_ != 0) { - unsigned __clz_f = __bits_per_word - __first.__ctz_; - difference_type __dn = std::min(static_cast(__clz_f), __n); - __n -= __dn; - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - __storage_type __b1 = *__first.__seg_ & __m; - *__first.__seg_ &= ~__m; - unsigned __clz_r = __bits_per_word - __result.__ctz_; - __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r); - __m = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn)); - __storage_type __b2 = *__result.__seg_ & __m; - *__result.__seg_ &= ~__m; - if (__result.__ctz_ > __first.__ctz_) { - unsigned __s = __result.__ctz_ - __first.__ctz_; - *__result.__seg_ |= __b1 << __s; - *__first.__seg_ |= __b2 >> __s; - } else { - unsigned __s = __first.__ctz_ - __result.__ctz_; - *__result.__seg_ |= __b1 >> __s; - *__first.__seg_ |= __b2 << __s; - } - __result.__seg_ += (__ddn + __result.__ctz_) / __bits_per_word; - __result.__ctz_ = static_cast((__ddn + __result.__ctz_) % __bits_per_word); - __dn -= __ddn; - if (__dn > 0) { - __m = ~__storage_type(0) >> (__bits_per_word - __dn); - __b2 = *__result.__seg_ & __m; - *__result.__seg_ &= ~__m; - unsigned __s = __first.__ctz_ + __ddn; - *__result.__seg_ |= __b1 >> __s; - *__first.__seg_ |= __b2 << __s; - __result.__ctz_ = static_cast(__dn); - } - ++__first.__seg_; - // __first.__ctz_ = 0; - } - // __first.__ctz_ == 0; - // do middle words - __storage_type __m = ~__storage_type(0) << __result.__ctz_; - unsigned __clz_r = __bits_per_word - __result.__ctz_; - for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_) { - __storage_type __b1 = *__first.__seg_; - __storage_type __b2 = *__result.__seg_ & __m; - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b1 << __result.__ctz_; - *__first.__seg_ = __b2 >> __result.__ctz_; - ++__result.__seg_; - __b2 = *__result.__seg_ & ~__m; - *__result.__seg_ &= __m; - *__result.__seg_ |= __b1 >> __clz_r; - *__first.__seg_ |= __b2 << __clz_r; - } - // do last word - if (__n > 0) { - __m = ~__storage_type(0) >> (__bits_per_word - __n); - __storage_type __b1 = *__first.__seg_ & __m; - *__first.__seg_ &= ~__m; - __storage_type __dn = std::min<__storage_type>(__n, __clz_r); - __m = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn)); - __storage_type __b2 = *__result.__seg_ & __m; - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b1 << __result.__ctz_; - *__first.__seg_ |= __b2 >> __result.__ctz_; - __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; - __result.__ctz_ = static_cast((__dn + __result.__ctz_) % __bits_per_word); - __n -= __dn; - if (__n > 0) { - __m = ~__storage_type(0) >> (__bits_per_word - __n); - __b2 = *__result.__seg_ & __m; - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b1 >> __dn; - *__first.__seg_ |= __b2 << __dn; - __result.__ctz_ = static_cast(__n); - } - } - } - return __result; -} - -template -inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cr, false> swap_ranges( - __bit_iterator<_Cl, false> __first1, __bit_iterator<_Cl, false> __last1, __bit_iterator<_Cr, false> __first2) { - if (__first1.__ctz_ == __first2.__ctz_) - return std::__swap_ranges_aligned(__first1, __last1, __first2); - return std::__swap_ranges_unaligned(__first1, __last1, __first2); -} - // rotate template @@ -752,14 +607,14 @@ private: template friend struct __copy_backward_impl; template - friend __bit_iterator<_Cr, false> + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Cr, false> __swap_ranges_aligned(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>); template - friend __bit_iterator<_Cr, false> + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Cr, false> __swap_ranges_unaligned(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>); - template - friend __bit_iterator<_Cr, false> - swap_ranges(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend pair<__bit_iterator<_Cl, false>, __bit_iterator<_Cr, false> > + __swap_ranges(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>); template _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> rotate(__bit_iterator<_Dp, false>, __bit_iterator<_Dp, false>, __bit_iterator<_Dp, false>); diff --git a/libcxx/test/benchmarks/algorithms/swap_ranges.bench.cpp b/libcxx/test/benchmarks/algorithms/swap_ranges.bench.cpp new file mode 100644 index 000000000000000..0c6dc10a6b7d686 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/swap_ranges.bench.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include +#include + +static void bm_ranges_swap_ranges_vb_aligned(benchmark::State& state) { + auto n = state.range(); + std::vector vec1(n, true); + std::vector vec2(n, false); + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::swap_ranges(vec1, vec2)); + benchmark::DoNotOptimize(&vec1); + benchmark::DoNotOptimize(&vec2); + } +} + +static void bm_ranges_swap_ranges_vb_unaligned(benchmark::State& state) { + auto n = state.range(); + std::vector vec1(n, true); + std::vector vec2(n + 8, true); + auto beg1 = std::ranges::begin(vec1); + auto end1 = std::ranges::end(vec1); + auto beg2 = std::ranges::begin(vec2) + 4; + auto end2 = std::ranges::end(vec2) - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::swap_ranges(beg1, end1, beg2, end2)); + benchmark::DoNotOptimize(&vec1); + benchmark::DoNotOptimize(&vec2); + } +} + +// Test std::ranges::swap_ranges for vector::iterator +BENCHMARK(bm_ranges_swap_ranges_vb_aligned)->RangeMultiplier(2)->Range(8, 1 << 20); +BENCHMARK(bm_ranges_swap_ranges_vb_unaligned)->Range(8, 1 << 20); + +static void bm_swap_ranges_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector vec1(n, true); + std::vector vec2(aligned ? n : n + 8, true); + auto beg1 = vec1.begin(); + auto end1 = vec1.end(); + auto beg2 = aligned ? vec2.begin() : vec2.begin() + 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::swap_ranges(beg1, end1, beg2)); + benchmark::DoNotOptimize(&vec1); + benchmark::DoNotOptimize(&vec2); + } +} + +static void bm_swap_ranges_vb_aligned(benchmark::State& state) { bm_swap_ranges_vb(state, true); } +static void bm_swap_ranges_vb_unaligned(benchmark::State& state) { bm_swap_ranges_vb(state, false); } + +// Test std::swap_ranges for vector::iterator +BENCHMARK(bm_swap_ranges_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_swap_ranges_vb_unaligned)->Range(8, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/iter_swap.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/iter_swap.pass.cpp index b3a9f5fc259ef7f..0394a48a0bb9a20 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/iter_swap.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/iter_swap.pass.cpp @@ -19,25 +19,23 @@ #include "test_macros.h" #if TEST_STD_VER > 17 -constexpr bool test_swap_constexpr() -{ - int i = 1; - int j = 2; - std::iter_swap(&i, &j); - return i == 2 && j == 1; +constexpr bool test_swap_constexpr() { + int i = 1; + int j = 2; + std::iter_swap(&i, &j); + return i == 2 && j == 1; } #endif // TEST_STD_VER > 17 -int main(int, char**) -{ - int i = 1; - int j = 2; - std::iter_swap(&i, &j); - assert(i == 2); - assert(j == 1); +int main(int, char**) { + int i = 1; + int j = 2; + std::iter_swap(&i, &j); + assert(i == 2); + assert(j == 1); #if TEST_STD_VER > 17 - static_assert(test_swap_constexpr()); + static_assert(test_swap_constexpr()); #endif // TEST_STD_VER > 17 return 0; diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp index a8d69b2832b4626..17914a928400f6c 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp @@ -23,13 +23,14 @@ #include #include #include +#include #include "test_iterators.h" constexpr void test_different_lengths() { - using Expected = std::ranges::swap_ranges_result; - int i[3] = {1, 2, 3}; - int j[1] = {4}; + using Expected = std::ranges::swap_ranges_result; + int i[3] = {1, 2, 3}; + int j[1] = {4}; std::same_as auto r = std::ranges::swap_ranges(i, i + 3, j, j + 1); assert(r.in1 == i + 1); assert(r.in2 == j + 1); @@ -64,8 +65,8 @@ constexpr void test_range() { std::array r1 = {1, 2, 3}; std::array r2 = {4, 5, 6}; - - std::same_as::iterator, std::array::iterator>> auto r = std::ranges::swap_ranges(r1, r2); + std::same_as::iterator, std::array::iterator>> auto r = + std::ranges::swap_ranges(r1, r2); assert(r.in1 == r1.end()); assert(r.in2 == r2.end()); @@ -110,13 +111,12 @@ constexpr void test_borrowed_input_range() { } constexpr void test_sentinel() { - int i[3] = {1, 2, 3}; - int j[3] = {4, 5, 6}; - using It = cpp17_input_iterator; - using Sent = sentinel_wrapper; - using Expected = std::ranges::swap_ranges_result; - std::same_as auto r = - std::ranges::swap_ranges(It(i), Sent(It(i + 3)), It(j), Sent(It(j + 3))); + int i[3] = {1, 2, 3}; + int j[3] = {4, 5, 6}; + using It = cpp17_input_iterator; + using Sent = sentinel_wrapper; + using Expected = std::ranges::swap_ranges_result; + std::same_as auto r = std::ranges::swap_ranges(It(i), Sent(It(i + 3)), It(j), Sent(It(j + 3))); assert(base(r.in1) == i + 3); assert(base(r.in2) == j + 3); assert(i[0] == 4); @@ -130,8 +130,8 @@ constexpr void test_sentinel() { template constexpr void test_iterators() { using Expected = std::ranges::swap_ranges_result; - int i[3] = {1, 2, 3}; - int j[3] = {4, 5, 6}; + int i[3] = {1, 2, 3}; + int j[3] = {4, 5, 6}; std::same_as auto r = std::ranges::swap_ranges(Iter1(i), sentinel_wrapper(Iter1(i + 3)), Iter2(j), sentinel_wrapper(Iter2(j + 3))); assert(base(r.in1) == i + 3); @@ -146,7 +146,7 @@ constexpr void test_iterators() { constexpr void test_rval_range() { { - using Expected = std::ranges::swap_ranges_result::iterator, std::ranges::dangling>; + using Expected = std::ranges::swap_ranges_result::iterator, std::ranges::dangling>; std::array r = {1, 2, 3}; std::same_as auto a = std::ranges::swap_ranges(r, std::array{4, 5, 6}); assert((r == std::array{4, 5, 6})); @@ -154,7 +154,7 @@ constexpr void test_rval_range() { } { std::array r = {1, 2, 3}; - using Expected = std::ranges::swap_ranges_result::iterator>; + using Expected = std::ranges::swap_ranges_result::iterator>; std::same_as auto b = std::ranges::swap_ranges(std::array{4, 5, 6}, r); assert((r == std::array{4, 5, 6})); assert(b.in2 == r.begin() + 3); @@ -170,6 +170,22 @@ constexpr void test_proxy_in_iterators() { test_iterators>, Out>(); } +template +constexpr void test_vector_bool() { + { // Test swap_ranges() with aligned bytes + std::vector f(N, false), t(N, true); + std::ranges::swap_ranges(f, t); + assert(std::all_of(f.begin(), f.end(), [](bool b) { return b; })); + assert(std::all_of(t.begin(), t.end(), [](bool b) { return !b; })); + } + { // Test swap_ranges() with unaligned bytes + std::vector f(N, false), t(N + 8, true); + std::ranges::swap_ranges(f.begin(), f.end(), t.begin() + 4, t.end() - 4); + assert(std::all_of(f.begin(), f.end(), [](bool b) { return b; })); + assert(std::all_of(t.begin() + 4, t.end() - 4, [](bool b) { return !b; })); + } +} + constexpr bool test() { test_range(); @@ -214,6 +230,16 @@ constexpr bool test() { test_borrowed_input_range(); test_rval_range(); + { // Test vector::iterator optimization + test_vector_bool<8>(); + test_vector_bool<19>(); + test_vector_bool<32>(); + test_vector_bool<49>(); + test_vector_bool<64>(); + test_vector_bool<199>(); + test_vector_bool<256>(); + } + return true; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/swap_ranges.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/swap_ranges.pass.cpp index 8bfbcd755e39f74..9a681a2611f1493 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/swap_ranges.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/swap_ranges.pass.cpp @@ -17,159 +17,175 @@ #include #include #include +#include #include "test_macros.h" #include "test_iterators.h" -template -void -test() -{ - int i[3] = {1, 2, 3}; - int j[3] = {4, 5, 6}; - Iter2 r = std::swap_ranges(Iter1(i), Iter1(i+3), Iter2(j)); - assert(base(r) == j+3); - assert(i[0] == 4); - assert(i[1] == 5); - assert(i[2] == 6); - assert(j[0] == 1); - assert(j[1] == 2); - assert(j[2] == 3); +template +void test() { + int i[3] = {1, 2, 3}; + int j[3] = {4, 5, 6}; + Iter2 r = std::swap_ranges(Iter1(i), Iter1(i + 3), Iter2(j)); + assert(base(r) == j + 3); + assert(i[0] == 4); + assert(i[1] == 5); + assert(i[2] == 6); + assert(j[0] == 1); + assert(j[1] == 2); + assert(j[2] == 3); } #if TEST_STD_VER >= 11 -template -void -test1() -{ - std::unique_ptr i[3]; - for (int k = 0; k < 3; ++k) - i[k].reset(new int(k+1)); - std::unique_ptr j[3]; - for (int k = 0; k < 3; ++k) - j[k].reset(new int(k+4)); - Iter2 r = std::swap_ranges(Iter1(i), Iter1(i+3), Iter2(j)); - assert(base(r) == j+3); - assert(*i[0] == 4); - assert(*i[1] == 5); - assert(*i[2] == 6); - assert(*j[0] == 1); - assert(*j[1] == 2); - assert(*j[2] == 3); +template +void test1() { + std::unique_ptr i[3]; + for (int k = 0; k < 3; ++k) + i[k].reset(new int(k + 1)); + std::unique_ptr j[3]; + for (int k = 0; k < 3; ++k) + j[k].reset(new int(k + 4)); + Iter2 r = std::swap_ranges(Iter1(i), Iter1(i + 3), Iter2(j)); + assert(base(r) == j + 3); + assert(*i[0] == 4); + assert(*i[1] == 5); + assert(*i[2] == 6); + assert(*j[0] == 1); + assert(*j[1] == 2); + assert(*j[2] == 3); } #endif // TEST_STD_VER >= 11 -void test2() -{ - { +void test2() { + { int src[2][2] = {{0, 1}, {2, 3}}; decltype(src) dest = {{9, 8}, {7, 6}}; std::swap(src, dest); - assert ( src[0][0] == 9 ); - assert ( src[0][1] == 8 ); - assert ( src[1][0] == 7 ); - assert ( src[1][1] == 6 ); + assert(src[0][0] == 9); + assert(src[0][1] == 8); + assert(src[1][0] == 7); + assert(src[1][1] == 6); - assert ( dest[0][0] == 0 ); - assert ( dest[0][1] == 1 ); - assert ( dest[1][0] == 2 ); - assert ( dest[1][1] == 3 ); - } + assert(dest[0][0] == 0); + assert(dest[0][1] == 1); + assert(dest[1][0] == 2); + assert(dest[1][1] == 3); + } - { + { int src[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}}; decltype(src) dest = {{9, 8, 7}, {6, 5, 4}, {3, 2, 1}}; std::swap(src, dest); - assert ( src[0][0] == 9 ); - assert ( src[0][1] == 8 ); - assert ( src[0][2] == 7 ); - assert ( src[1][0] == 6 ); - assert ( src[1][1] == 5 ); - assert ( src[1][2] == 4 ); - assert ( src[2][0] == 3 ); - assert ( src[2][1] == 2 ); - assert ( src[2][2] == 1 ); - - assert ( dest[0][0] == 0 ); - assert ( dest[0][1] == 1 ); - assert ( dest[0][2] == 2 ); - assert ( dest[1][0] == 3 ); - assert ( dest[1][1] == 4 ); - assert ( dest[1][2] == 5 ); - assert ( dest[2][0] == 6 ); - assert ( dest[2][1] == 7 ); - assert ( dest[2][2] == 8 ); - } + assert(src[0][0] == 9); + assert(src[0][1] == 8); + assert(src[0][2] == 7); + assert(src[1][0] == 6); + assert(src[1][1] == 5); + assert(src[1][2] == 4); + assert(src[2][0] == 3); + assert(src[2][1] == 2); + assert(src[2][2] == 1); + + assert(dest[0][0] == 0); + assert(dest[0][1] == 1); + assert(dest[0][2] == 2); + assert(dest[1][0] == 3); + assert(dest[1][1] == 4); + assert(dest[1][2] == 5); + assert(dest[2][0] == 6); + assert(dest[2][1] == 7); + assert(dest[2][2] == 8); + } } #if TEST_STD_VER > 17 -constexpr bool test_swap_constexpr() -{ - int i[3] = {1, 2, 3}; - int j[3] = {4, 5, 6}; - std::swap_ranges(i, i+3, j); - return i[0] == 4 && - i[1] == 5 && - i[2] == 6 && - j[0] == 1 && - j[1] == 2 && - j[2] == 3; +constexpr bool test_swap_constexpr() { + int i[3] = {1, 2, 3}; + int j[3] = {4, 5, 6}; + std::swap_ranges(i, i + 3, j); + return i[0] == 4 && i[1] == 5 && i[2] == 6 && j[0] == 1 && j[1] == 2 && j[2] == 3; } #endif // TEST_STD_VER > 17 -int main(int, char**) -{ - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); +template +TEST_CONSTEXPR_CXX20 void test_vector_bool() { + std::vector f(N, false), t(N, true); + { // Test swap_ranges() with aligned bytes + std::vector f1 = f, t1 = t; + std::swap_ranges(f1.begin(), f1.end(), t1.begin()); + assert(f1 == t); + assert(t1 == f); + } + { // Test swap_ranges() with unaligned bytes + std::vector f1(N, false), t1(N + 8, true); + std::swap_ranges(f1.begin(), f1.end(), t1.begin() + 4); + assert(std::equal(f1.begin(), f1.end(), t.begin())); + assert(std::equal(t1.begin() + 4, t1.end() - 4, f.begin())); + } +} + +int main(int, char**) { + test, forward_iterator >(); + test, bidirectional_iterator >(); + test, random_access_iterator >(); + test, int*>(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); + test, forward_iterator >(); + test, bidirectional_iterator >(); + test, random_access_iterator >(); + test, int*>(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); + test, forward_iterator >(); + test, bidirectional_iterator >(); + test, random_access_iterator >(); + test, int*>(); - test >(); - test >(); - test >(); - test(); + test >(); + test >(); + test >(); + test(); #if TEST_STD_VER >= 11 - test1*>, forward_iterator*> >(); - test1*>, bidirectional_iterator*> >(); - test1*>, random_access_iterator*> >(); - test1*>, std::unique_ptr*>(); - - test1*>, forward_iterator*> >(); - test1*>, bidirectional_iterator*> >(); - test1*>, random_access_iterator*> >(); - test1*>, std::unique_ptr*>(); - - test1*>, forward_iterator*> >(); - test1*>, bidirectional_iterator*> >(); - test1*>, random_access_iterator*> >(); - test1*>, std::unique_ptr*>(); - - test1*, forward_iterator*> >(); - test1*, bidirectional_iterator*> >(); - test1*, random_access_iterator*> >(); - test1*, std::unique_ptr*>(); + test1*>, forward_iterator*> >(); + test1*>, bidirectional_iterator*> >(); + test1*>, random_access_iterator*> >(); + test1*>, std::unique_ptr*>(); + + test1*>, forward_iterator*> >(); + test1*>, bidirectional_iterator*> >(); + test1*>, random_access_iterator*> >(); + test1*>, std::unique_ptr*>(); + + test1*>, forward_iterator*> >(); + test1*>, bidirectional_iterator*> >(); + test1*>, random_access_iterator*> >(); + test1*>, std::unique_ptr*>(); + + test1*, forward_iterator*> >(); + test1*, bidirectional_iterator*> >(); + test1*, random_access_iterator*> >(); + test1*, std::unique_ptr*>(); #endif // TEST_STD_VER >= 11 #if TEST_STD_VER > 17 - static_assert(test_swap_constexpr()); + static_assert(test_swap_constexpr()); #endif // TEST_STD_VER > 17 - test2(); + test2(); + + { // Test vector::iterator optimization + test_vector_bool<8>(); + test_vector_bool<19>(); + test_vector_bool<32>(); + test_vector_bool<49>(); + test_vector_bool<64>(); + test_vector_bool<199>(); + test_vector_bool<256>(); + } return 0; } From libcxx-commits at lists.llvm.org Mon Feb 3 23:20:03 2025 From: libcxx-commits at lists.llvm.org (=?UTF-8?B?0JTQvNC40YLRgNC40Lkg0JjQt9Cy0L7Qu9C+0LI=?= via libcxx-commits) Date: Mon, 03 Feb 2025 23:20:03 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Support `constexpr` for `std::stable_sort` in radix sort branch (PR #125284) In-Reply-To: Message-ID: <67a1bfa3.170a0220.2254e5.3203@mx.google.com> https://github.com/izvolov updated https://github.com/llvm/llvm-project/pull/125284 >From 6dbc30721a7378878da01faaf0bad6795a4a0302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=98=D0=B7?= =?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BE=D0=B2?= Date: Tue, 4 Feb 2025 10:19:19 +0300 Subject: [PATCH 1/2] constexpr --- libcxx/include/__algorithm/radix_sort.h | 24 ++++++++++++------------ libcxx/include/__algorithm/stable_sort.h | 7 +++++++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/libcxx/include/__algorithm/radix_sort.h b/libcxx/include/__algorithm/radix_sort.h index de6927995e74c8..89df4e19fd00fb 100644 --- a/libcxx/include/__algorithm/radix_sort.h +++ b/libcxx/include/__algorithm/radix_sort.h @@ -67,7 +67,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 14 template -_LIBCPP_HIDE_FROM_ABI pair<_OutputIterator, __iter_value_type<_InputIterator>> +_LIBCPP_HIDE_FROM_ABI constexpr pair<_OutputIterator, __iter_value_type<_InputIterator>> __partial_sum_max(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { if (__first == __last) return {__result, 0}; @@ -109,7 +109,7 @@ struct __counting_sort_traits { }; template -_LIBCPP_HIDE_FROM_ABI auto __nth_radix(size_t __radix_number, _Radix __radix, _Integer __n) { +_LIBCPP_HIDE_FROM_ABI constexpr auto __nth_radix(size_t __radix_number, _Radix __radix, _Integer __n) { static_assert(is_unsigned<_Integer>::value); using __traits = __counting_sort_traits<_Integer, _Radix>; @@ -117,7 +117,7 @@ _LIBCPP_HIDE_FROM_ABI auto __nth_radix(size_t __radix_number, _Radix __radix, _I } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __collect(_ForwardIterator __first, _ForwardIterator __last, _Map __map, _RandomAccessIterator __counters) { using __value_type = __iter_value_type<_ForwardIterator>; using __traits = __counting_sort_traits<__value_type, _Map>; @@ -129,7 +129,7 @@ __collect(_ForwardIterator __first, _ForwardIterator __last, _Map __map, _Random } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __dispose(_ForwardIterator __first, _ForwardIterator __last, _RandomAccessIterator1 __result, @@ -147,7 +147,7 @@ template -_LIBCPP_HIDE_FROM_ABI bool __collect_impl( +_LIBCPP_HIDE_FROM_ABI constexpr bool __collect_impl( _ForwardIterator __first, _ForwardIterator __last, _Map __map, @@ -177,7 +177,7 @@ _LIBCPP_HIDE_FROM_ABI bool __collect_impl( } template -_LIBCPP_HIDE_FROM_ABI bool +_LIBCPP_HIDE_FROM_ABI constexpr bool __collect(_ForwardIterator __first, _ForwardIterator __last, _Map __map, @@ -191,7 +191,7 @@ __collect(_ForwardIterator __first, } template -_LIBCPP_HIDE_FROM_ABI void __dispose_backward( +_LIBCPP_HIDE_FROM_ABI constexpr void __dispose_backward( _BidirectionalIterator __first, _BidirectionalIterator __last, _RandomAccessIterator1 __result, @@ -206,7 +206,7 @@ _LIBCPP_HIDE_FROM_ABI void __dispose_backward( } template -_LIBCPP_HIDE_FROM_ABI _RandomAccessIterator +_LIBCPP_HIDE_FROM_ABI constexpr _RandomAccessIterator __counting_sort_impl(_ForwardIterator __first, _ForwardIterator __last, _RandomAccessIterator __result, _Map __map) { using __value_type = __iter_value_type<_ForwardIterator>; using __traits = __counting_sort_traits<__value_type, _Map>; @@ -225,7 +225,7 @@ template , _Map, _Radix>::__radix_count == 1, int> = 0> -_LIBCPP_HIDE_FROM_ABI void __radix_sort_impl( +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort_impl( _RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer, @@ -245,7 +245,7 @@ template < class _Radix, enable_if_t< __radix_sort_traits<__iter_value_type<_RandomAccessIterator1>, _Map, _Radix>::__radix_count % 2 == 0, int> = 0 > -_LIBCPP_HIDE_FROM_ABI void __radix_sort_impl( +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort_impl( _RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer_begin, @@ -307,7 +307,7 @@ struct __low_byte_fn { }; template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer, @@ -318,7 +318,7 @@ __radix_sort(_RandomAccessIterator1 __first, } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer) { std::__radix_sort(__first, __last, __buffer, __identity{}, __low_byte_fn{}); } diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 3cfbcf08d2c5c4..49d3cca2526ead 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -25,6 +25,7 @@ #include <__memory/unique_temporary_buffer.h> #include <__type_traits/desugars_to.h> #include <__type_traits/enable_if.h> +#include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_integral.h> #include <__type_traits/is_same.h> #include <__type_traits/is_trivially_assignable.h> @@ -253,6 +254,12 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort( if constexpr (__allowed_radix_sort) { if (__len <= __buff_size && __len >= static_cast(__radix_sort_min_bound()) && __len <= static_cast(__radix_sort_max_bound())) { + if (__libcpp_is_constant_evaluated()) { + for (auto* __p = __buff; __p < __buff + __buff_size; ++__p) { + std::__construct_at(__p); + } + } + std::__radix_sort(__first, __last, __buff); return; } >From 08a6649df23c14f300ae6fc31c30b36e4ae2525e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=98=D0=B7?= =?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BE=D0=B2?= Date: Tue, 4 Feb 2025 10:19:26 +0300 Subject: [PATCH 2/2] test --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index b3b458808c44ad..4ee1d795a23b26 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -199,6 +199,8 @@ int main(int, char**) { #if TEST_STD_VER >= 26 static_assert(test()); static_assert(test()); + // test constexprness of radix sort branch + static_assert(test()); #endif return 0; } From libcxx-commits at lists.llvm.org Tue Feb 4 01:31:00 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Tue, 04 Feb 2025 01:31:00 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Support `constexpr` for `std::stable_sort` in radix sort branch (PR #125284) Message-ID: <67a1de54.170a0220.306b33.3314@mx.google.com> =?utf-8?b?0JTQvNC40YLRgNC40Lkg0JjQtw==?= Message-ID: In-Reply-To: https://github.com/philnik777 approved this pull request. https://github.com/llvm/llvm-project/pull/125284 From libcxx-commits at lists.llvm.org Tue Feb 4 01:31:35 2025 From: libcxx-commits at lists.llvm.org (=?UTF-8?B?0JTQvNC40YLRgNC40Lkg0JjQt9Cy0L7Qu9C+0LI=?= via libcxx-commits) Date: Tue, 04 Feb 2025 01:31:35 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Support `constexpr` for `std::stable_sort` in radix sort branch (PR #125284) In-Reply-To: Message-ID: <67a1de77.a70a0220.20688e.62c8@mx.google.com> https://github.com/izvolov updated https://github.com/llvm/llvm-project/pull/125284 >From 6dbc30721a7378878da01faaf0bad6795a4a0302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=98=D0=B7?= =?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BE=D0=B2?= Date: Tue, 4 Feb 2025 10:19:19 +0300 Subject: [PATCH 1/3] constexpr --- libcxx/include/__algorithm/radix_sort.h | 24 ++++++++++++------------ libcxx/include/__algorithm/stable_sort.h | 7 +++++++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/libcxx/include/__algorithm/radix_sort.h b/libcxx/include/__algorithm/radix_sort.h index de6927995e74c8..89df4e19fd00fb 100644 --- a/libcxx/include/__algorithm/radix_sort.h +++ b/libcxx/include/__algorithm/radix_sort.h @@ -67,7 +67,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 14 template -_LIBCPP_HIDE_FROM_ABI pair<_OutputIterator, __iter_value_type<_InputIterator>> +_LIBCPP_HIDE_FROM_ABI constexpr pair<_OutputIterator, __iter_value_type<_InputIterator>> __partial_sum_max(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { if (__first == __last) return {__result, 0}; @@ -109,7 +109,7 @@ struct __counting_sort_traits { }; template -_LIBCPP_HIDE_FROM_ABI auto __nth_radix(size_t __radix_number, _Radix __radix, _Integer __n) { +_LIBCPP_HIDE_FROM_ABI constexpr auto __nth_radix(size_t __radix_number, _Radix __radix, _Integer __n) { static_assert(is_unsigned<_Integer>::value); using __traits = __counting_sort_traits<_Integer, _Radix>; @@ -117,7 +117,7 @@ _LIBCPP_HIDE_FROM_ABI auto __nth_radix(size_t __radix_number, _Radix __radix, _I } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __collect(_ForwardIterator __first, _ForwardIterator __last, _Map __map, _RandomAccessIterator __counters) { using __value_type = __iter_value_type<_ForwardIterator>; using __traits = __counting_sort_traits<__value_type, _Map>; @@ -129,7 +129,7 @@ __collect(_ForwardIterator __first, _ForwardIterator __last, _Map __map, _Random } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __dispose(_ForwardIterator __first, _ForwardIterator __last, _RandomAccessIterator1 __result, @@ -147,7 +147,7 @@ template -_LIBCPP_HIDE_FROM_ABI bool __collect_impl( +_LIBCPP_HIDE_FROM_ABI constexpr bool __collect_impl( _ForwardIterator __first, _ForwardIterator __last, _Map __map, @@ -177,7 +177,7 @@ _LIBCPP_HIDE_FROM_ABI bool __collect_impl( } template -_LIBCPP_HIDE_FROM_ABI bool +_LIBCPP_HIDE_FROM_ABI constexpr bool __collect(_ForwardIterator __first, _ForwardIterator __last, _Map __map, @@ -191,7 +191,7 @@ __collect(_ForwardIterator __first, } template -_LIBCPP_HIDE_FROM_ABI void __dispose_backward( +_LIBCPP_HIDE_FROM_ABI constexpr void __dispose_backward( _BidirectionalIterator __first, _BidirectionalIterator __last, _RandomAccessIterator1 __result, @@ -206,7 +206,7 @@ _LIBCPP_HIDE_FROM_ABI void __dispose_backward( } template -_LIBCPP_HIDE_FROM_ABI _RandomAccessIterator +_LIBCPP_HIDE_FROM_ABI constexpr _RandomAccessIterator __counting_sort_impl(_ForwardIterator __first, _ForwardIterator __last, _RandomAccessIterator __result, _Map __map) { using __value_type = __iter_value_type<_ForwardIterator>; using __traits = __counting_sort_traits<__value_type, _Map>; @@ -225,7 +225,7 @@ template , _Map, _Radix>::__radix_count == 1, int> = 0> -_LIBCPP_HIDE_FROM_ABI void __radix_sort_impl( +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort_impl( _RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer, @@ -245,7 +245,7 @@ template < class _Radix, enable_if_t< __radix_sort_traits<__iter_value_type<_RandomAccessIterator1>, _Map, _Radix>::__radix_count % 2 == 0, int> = 0 > -_LIBCPP_HIDE_FROM_ABI void __radix_sort_impl( +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort_impl( _RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer_begin, @@ -307,7 +307,7 @@ struct __low_byte_fn { }; template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer, @@ -318,7 +318,7 @@ __radix_sort(_RandomAccessIterator1 __first, } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer) { std::__radix_sort(__first, __last, __buffer, __identity{}, __low_byte_fn{}); } diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 3cfbcf08d2c5c4..49d3cca2526ead 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -25,6 +25,7 @@ #include <__memory/unique_temporary_buffer.h> #include <__type_traits/desugars_to.h> #include <__type_traits/enable_if.h> +#include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_integral.h> #include <__type_traits/is_same.h> #include <__type_traits/is_trivially_assignable.h> @@ -253,6 +254,12 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort( if constexpr (__allowed_radix_sort) { if (__len <= __buff_size && __len >= static_cast(__radix_sort_min_bound()) && __len <= static_cast(__radix_sort_max_bound())) { + if (__libcpp_is_constant_evaluated()) { + for (auto* __p = __buff; __p < __buff + __buff_size; ++__p) { + std::__construct_at(__p); + } + } + std::__radix_sort(__first, __last, __buff); return; } >From 08a6649df23c14f300ae6fc31c30b36e4ae2525e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=98=D0=B7?= =?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BE=D0=B2?= Date: Tue, 4 Feb 2025 10:19:26 +0300 Subject: [PATCH 2/3] test --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index b3b458808c44ad..4ee1d795a23b26 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -199,6 +199,8 @@ int main(int, char**) { #if TEST_STD_VER >= 26 static_assert(test()); static_assert(test()); + // test constexprness of radix sort branch + static_assert(test()); #endif return 0; } >From 6bf69ed5fd73469862cf5750c35cb6ef2c08b457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=98=D0=B7?= =?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BE=D0=B2?= Date: Tue, 4 Feb 2025 12:31:12 +0300 Subject: [PATCH 3/3] include --- libcxx/include/__algorithm/radix_sort.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__algorithm/radix_sort.h b/libcxx/include/__algorithm/radix_sort.h index 89df4e19fd00fb..f6d9fb1ad7ca99 100644 --- a/libcxx/include/__algorithm/radix_sort.h +++ b/libcxx/include/__algorithm/radix_sort.h @@ -33,6 +33,7 @@ #include <__bit/countl.h> #include <__config> #include <__functional/identity.h> +#include <__iterator/access.h> #include <__iterator/distance.h> #include <__iterator/iterator_traits.h> #include <__iterator/move_iterator.h> From libcxx-commits at lists.llvm.org Tue Feb 4 05:05:39 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Tue, 04 Feb 2025 05:05:39 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Don't try to wait on a thread that hasn't started in std::async (PR #125433) In-Reply-To: Message-ID: <67a210a3.630a0220.fe1ba.772d@mx.google.com> https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/125433 >From d1944d4d23f75ae6bb97dd7fd3a96b989ae0e050 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Sun, 2 Feb 2025 22:07:04 +0100 Subject: [PATCH] [libc++] Don't try to wait on a thread that hasn't started in std::async --- libcxx/include/future | 6 ++- .../thread_create_failure.pass.cpp | 51 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp diff --git a/libcxx/include/future b/libcxx/include/future index db1f624244b8f7..514d4c3d633d6c 100644 --- a/libcxx/include/future +++ b/libcxx/include/future @@ -865,7 +865,8 @@ void __async_assoc_state<_Rp, _Fp>::__execute() { template void __async_assoc_state<_Rp, _Fp>::__on_zero_shared() _NOEXCEPT { - this->wait(); + if (base::__state_ & base::__constructed) + this->wait(); base::__on_zero_shared(); } @@ -902,7 +903,8 @@ void __async_assoc_state::__execute() { template void __async_assoc_state::__on_zero_shared() _NOEXCEPT { - this->wait(); + if (base::__state_ & base::__constructed) + this->wait(); base::__on_zero_shared(); } diff --git a/libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp b/libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp new file mode 100644 index 00000000000000..c4c30ba0ceba25 --- /dev/null +++ b/libcxx/test/std/thread/futures/futures.async/thread_create_failure.pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: no-threads, no-exceptions + +// UNSUPPORTED: c++03 + +// There is no way to limit the number of threads on windows +// UNSUPPORTED: msvc + +// AIX doesn't seem to complain if the thread limit is reached. +// XFAIL: target={{.+}}-aix{{.*}} + +#include +#include +#include + +#if __has_include() +# include +# ifdef RLIMIT_NPROC +void force_thread_creation_failure() { + rlimit lim = {1, 1}; + setrlimit(RLIMIT_NPROC, &lim); +} +# else +# error "No known way to force only one thread being available" +# endif +#else +# error "No known way to force only one thread being available" +#endif + +int main() { + force_thread_creation_failure(); + + try { + auto fut = std::async(std::launch::async, [] { return 1; }); + assert(false); + } catch (const std::system_error&) { + } + + try { + auto fut = std::async(std::launch::async, [] { return; }); + assert(false); + } catch (const std::system_error&) { + } +} From libcxx-commits at lists.llvm.org Tue Feb 4 05:11:55 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Tue, 04 Feb 2025 05:11:55 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add a utility for checking the output of commands (PR #65917) In-Reply-To: Message-ID: <67a2121b.170a0220.1bc2f3.5d3e@mx.google.com> https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/65917 >From 8b35db5d35c7a9096cd38206f7e8d906dfb497c6 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Wed, 6 Sep 2023 08:31:36 -0700 Subject: [PATCH] [libc++] Add a utility for checking the output of commands --- libcxx/test/configs/cmake-bridge.cfg.in | 1 + .../copy_move_codegen.sh.cpp | 21 +++ .../clang_tidy/proper_version_checks.sh.cpp | 29 ++++ .../utility/unreachable.codegen.sh.cpp | 24 ++++ libcxx/test/tools/CMakeLists.txt | 6 +- libcxx/test/tools/check_output/CMakeLists.txt | 15 ++ .../test/tools/check_output/check_output.cpp | 129 ++++++++++++++++++ .../proper_version_checks.cpp | 2 - 8 files changed, 223 insertions(+), 4 deletions(-) create mode 100644 libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp create mode 100644 libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp create mode 100644 libcxx/test/libcxx/utilities/utility/unreachable.codegen.sh.cpp create mode 100644 libcxx/test/tools/check_output/CMakeLists.txt create mode 100644 libcxx/test/tools/check_output/check_output.cpp diff --git a/libcxx/test/configs/cmake-bridge.cfg.in b/libcxx/test/configs/cmake-bridge.cfg.in index 61f821a7e4f6b8..3bbd1356ad20da 100644 --- a/libcxx/test/configs/cmake-bridge.cfg.in +++ b/libcxx/test/configs/cmake-bridge.cfg.in @@ -31,3 +31,4 @@ config.substitutions.append(('%{lib-dir}', '@LIBCXX_TESTING_INSTALL_PREFIX@/@LIB config.substitutions.append(('%{module-dir}', '@LIBCXX_TESTING_INSTALL_PREFIX@/@LIBCXX_INSTALL_MODULES_DIR@')) config.substitutions.append(('%{test-tools-dir}', '@LIBCXX_TEST_TOOLS_PATH@')) config.substitutions.append(('%{benchmark_flags}', '-I @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/include -L @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/lib -L @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/lib64 -l benchmark')) +config.substitutions.append(('%{check-output}', os.path.join('@LIBCXX_BINARY_DIR@', 'bin/check_output') + " %s")) diff --git a/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp new file mode 100644 index 00000000000000..02191c9b1b37ae --- /dev/null +++ b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// This test is checking the LLVM IR +// REQUIRES: clang + +// RUN: %{cxx} %s %{flags} %{compile_flags} -O3 -c -S -emit-llvm -o - | %{check-output} + +#include + +int* test1(int* first, int* last, int* out) { + // CHECK: define + // CHECK-SAME: test1 + // CHECK: tail call void @llvm.memmove + return std::copy(first, last, out); +} diff --git a/libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp b/libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp new file mode 100644 index 00000000000000..54071dcc7f1698 --- /dev/null +++ b/libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-clang-tidy + +// RUN: %{clang-tidy} %s -header-filter=.* --checks='-*,libcpp-cpp-version-check' --load=%{test-tools-dir}/clang_tidy_checks/libcxx-tidy.plugin -- %{compile_flags} -fno-modules 2>&1 | %{check-output} + +#include <__config> + +// CHECK: warning: _LIBCPP_STD_VER >= version should be used instead of _LIBCPP_STD_VER > prev_version +#if _LIBCPP_STD_VER > 14 +#endif + +// CHECK: warning: Use _LIBCPP_STD_VER instead of __cplusplus to constrain based on the C++ version +#if __cplusplus >= 201103L +#endif + +// CHECK: warning: _LIBCPP_STD_VER >= 11 is always true. Did you mean '#ifndef _LIBCPP_CXX03_LANG'? +#if _LIBCPP_STD_VER >= 11 +#endif + +// CHECK: warning: Not a valid value for _LIBCPP_STD_VER. Use 14, 17, 20, 23, or 26 +#if _LIBCPP_STD_VER >= 12 +#endif diff --git a/libcxx/test/libcxx/utilities/utility/unreachable.codegen.sh.cpp b/libcxx/test/libcxx/utilities/utility/unreachable.codegen.sh.cpp new file mode 100644 index 00000000000000..1cf503d68e092a --- /dev/null +++ b/libcxx/test/libcxx/utilities/utility/unreachable.codegen.sh.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// This test is checking the LLVM IR +// REQUIRES: clang + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// RUN: %{cxx} %s %{flags} %{compile_flags} -Wno-missing-noreturn -O3 -c -S -emit-llvm -o - | %{check-output} + +#include + +void test() { + // CHECK: define dso_local void + // CHECK-SAME: test + // CHECK-NEXT: unreachable + // CHECK-NEXT: } + std::unreachable(); +} diff --git a/libcxx/test/tools/CMakeLists.txt b/libcxx/test/tools/CMakeLists.txt index 6d99c53ad46d9f..d1d7442e99d004 100644 --- a/libcxx/test/tools/CMakeLists.txt +++ b/libcxx/test/tools/CMakeLists.txt @@ -3,6 +3,8 @@ set(LIBCXX_TEST_TOOLS_PATH ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") message(STATUS "Clang-tidy tests are disabled due to non-clang based compiler.") - return() +else() + add_subdirectory(clang_tidy_checks) endif() -add_subdirectory(clang_tidy_checks) + +add_subdirectory(check_output) diff --git a/libcxx/test/tools/check_output/CMakeLists.txt b/libcxx/test/tools/check_output/CMakeLists.txt new file mode 100644 index 00000000000000..3dd3feee298e66 --- /dev/null +++ b/libcxx/test/tools/check_output/CMakeLists.txt @@ -0,0 +1,15 @@ + +add_executable(check_output check_output.cpp) + +# put the binary into /bin +set_target_properties(check_output PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${LIBCXX_BINARY_DIR}/bin") + +# set the language mode +set_target_properties(check_output PROPERTIES + CXX_STANDARD 23 + CXX_STANDARD_REQUIRED YES + CXX_EXTENSIONS NO) + +target_compile_options(check_output PRIVATE -Werror=missing-prototypes) + +add_dependencies(cxx-test-depends check_output) diff --git a/libcxx/test/tools/check_output/check_output.cpp b/libcxx/test/tools/check_output/check_output.cpp new file mode 100644 index 00000000000000..94a84a9e40290b --- /dev/null +++ b/libcxx/test/tools/check_output/check_output.cpp @@ -0,0 +1,129 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include +#include + +using namespace std::string_view_literals; + +enum class Result { + success, + mismatch, + no_match_found, + unknown_matcher, + invalid_use, +}; + +namespace co { +namespace { +[[noreturn]] void exit(Result result) { std::exit(static_cast(result)); } + +[[noreturn]] void print_failure(int line, std::string_view stdin_content, std::string_view matcher) { + std::cout << "Failed to match: `" << matcher << "`\nRemaining data:\n" << stdin_content << '\n'; + co::exit(Result::mismatch); +} + +bool is_newline(char c) { return c == '\n'; } + +bool isblank(char c) { return std::isblank(c); } + +bool consume_front(std::string_view& sv, std::string_view start) { + if (!sv.starts_with(start)) + return false; + sv.remove_prefix(start.size()); + return true; +} +} // namespace +} // namespace co + +int main(int argc, char** argv) { + if (argc != 2) { + std::cerr << "check_output has to be used as ` | ./check_output %s`\n"; + co::exit(Result::invalid_use); + } + + std::string file_content_data = [&] { + std::ifstream file(argv[1]); + if (!file) { + std::cerr << "Failed to open file: " << argv[1] << '\n'; + co::exit(Result::invalid_use); + } + return std::string{std::istreambuf_iterator{file}, {}}; + }(); + std::string_view file_content = file_content_data; // Don't copy the data around all the time + + std::string stdin_content_data = [&] { + std::cin >> std::noskipws; + return std::string{std::istream_iterator{std::cin}, {}}; + }(); + std::string_view stdin_content = stdin_content_data; // Don't copy the data around all the time + + size_t match_count = 0; + auto drop_blanks = std::views::drop_while(co::isblank); + + while (!file_content.empty()) { + auto marker = std::ranges::search(file_content, "// CHECK"sv); + if (marker.empty()) { + if (match_count == 0) { + std::cerr << "No matcher found!\n"; + co::exit(Result::no_match_found); + } + co::exit(Result::success); + } + file_content.remove_prefix(marker.end() - file_content.begin()); + + const auto get_match = [&]() { + return std::string_view(file_content.begin(), std::ranges::find(file_content, '\n')); + }; + + if (co::consume_front(file_content, ":")) { + auto match = get_match(); + auto found = std::ranges::search( + stdin_content | std::views::drop_while(std::not_fn(co::is_newline)) | std::views::drop(1), + match | drop_blanks); + if (found.empty()) { + co::print_failure(1, stdin_content, match); + } + ++match_count; + stdin_content.remove_prefix(found.end() - stdin_content.begin()); + } else if (co::consume_front(file_content, "-SAME:")) { + auto match = get_match(); + auto haystack = std::string_view(stdin_content.begin(), std::ranges::find(stdin_content, '\n')); + auto found = std::ranges::search(haystack, match | drop_blanks); + if (found.empty()) { + co::print_failure(1, stdin_content, match); + } + stdin_content.remove_prefix(found.end() - stdin_content.begin()); + } else if (co::consume_front(file_content, "-NEXT:")) { + auto match = get_match(); + auto haystack = [&] { + auto begin = std::ranges::find(stdin_content, '\n'); + if (begin == stdin_content.end()) { + co::print_failure(1, stdin_content, match); + } + ++begin; + return std::string_view(begin, std::ranges::find(begin, stdin_content.end(), '\n')); + }(); + auto found = std::ranges::search(haystack, match | drop_blanks); + if (found.empty()) + co::print_failure(1, stdin_content, match); + stdin_content.remove_prefix(found.end() - stdin_content.begin()); + } else { + std::cerr << "Unkown matcher type " + << std::string_view(file_content.begin(), std::ranges::find(file_content, ':')) << " found\n"; + co::exit(Result::unknown_matcher); + } + } + + co::exit(Result::success); +} diff --git a/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp b/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp index ebd0d8892fa94c..44493824944b04 100644 --- a/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp +++ b/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp @@ -36,8 +36,6 @@ class proper_version_checks_callbacks : public clang::PPCallbacks { clang::CharSourceRange::getTokenRange(condition_range), preprocessor_.getSourceManager(), preprocessor_.getLangOpts()); - if (preprocessor_.getSourceManager().isInMainFile(location)) - return; if (condition == "__cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)") return; From libcxx-commits at lists.llvm.org Tue Feb 4 07:38:21 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 07:38:21 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Decrease instantiation cost of __constexpr_memmove (PR #125109) In-Reply-To: Message-ID: <67a2346d.050a0220.fdf57.021e@mx.google.com> https://github.com/ldionne approved this pull request. https://github.com/llvm/llvm-project/pull/125109 From libcxx-commits at lists.llvm.org Tue Feb 4 07:59:27 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Tue, 04 Feb 2025 07:59:27 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add a utility for checking the output of commands (PR #65917) In-Reply-To: Message-ID: <67a2395f.170a0220.89343.a5a8@mx.google.com> https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/65917 >From 5df916ddfa31bdb29a4e0f9f55b31b5d517e7707 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Wed, 6 Sep 2023 08:31:36 -0700 Subject: [PATCH] [libc++] Add a utility for checking the output of commands --- libcxx/test/configs/cmake-bridge.cfg.in | 1 + .../copy_move_codegen.sh.cpp | 23 ++++ .../clang_tidy/proper_version_checks.sh.cpp | 29 ++++ .../utility/unreachable.codegen.sh.cpp | 26 ++++ libcxx/test/tools/CMakeLists.txt | 6 +- libcxx/test/tools/check_output/CMakeLists.txt | 15 ++ .../test/tools/check_output/check_output.cpp | 129 ++++++++++++++++++ .../proper_version_checks.cpp | 2 - 8 files changed, 227 insertions(+), 4 deletions(-) create mode 100644 libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp create mode 100644 libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp create mode 100644 libcxx/test/libcxx/utilities/utility/unreachable.codegen.sh.cpp create mode 100644 libcxx/test/tools/check_output/CMakeLists.txt create mode 100644 libcxx/test/tools/check_output/check_output.cpp diff --git a/libcxx/test/configs/cmake-bridge.cfg.in b/libcxx/test/configs/cmake-bridge.cfg.in index 61f821a7e4f6b8..3bbd1356ad20da 100644 --- a/libcxx/test/configs/cmake-bridge.cfg.in +++ b/libcxx/test/configs/cmake-bridge.cfg.in @@ -31,3 +31,4 @@ config.substitutions.append(('%{lib-dir}', '@LIBCXX_TESTING_INSTALL_PREFIX@/@LIB config.substitutions.append(('%{module-dir}', '@LIBCXX_TESTING_INSTALL_PREFIX@/@LIBCXX_INSTALL_MODULES_DIR@')) config.substitutions.append(('%{test-tools-dir}', '@LIBCXX_TEST_TOOLS_PATH@')) config.substitutions.append(('%{benchmark_flags}', '-I @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/include -L @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/lib -L @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/lib64 -l benchmark')) +config.substitutions.append(('%{check-output}', os.path.join('@LIBCXX_BINARY_DIR@', 'bin/check_output') + " %s")) diff --git a/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp new file mode 100644 index 00000000000000..4c8ef301562464 --- /dev/null +++ b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// This test is checking the LLVM IR +// REQUIRES: clang + +// UNSUPPORTED: asan, tsan, ubsan, msan + +// RUN: %{cxx} %s %{flags} %{compile_flags} -O3 -c -S -emit-llvm -o - | %{check-output} + +#include + +int* test1(int* first, int* last, int* out) { + // CHECK: define + // CHECK-SAME: test1 + // CHECK: tail call void @llvm.memmove + return std::copy(first, last, out); +} diff --git a/libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp b/libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp new file mode 100644 index 00000000000000..54071dcc7f1698 --- /dev/null +++ b/libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-clang-tidy + +// RUN: %{clang-tidy} %s -header-filter=.* --checks='-*,libcpp-cpp-version-check' --load=%{test-tools-dir}/clang_tidy_checks/libcxx-tidy.plugin -- %{compile_flags} -fno-modules 2>&1 | %{check-output} + +#include <__config> + +// CHECK: warning: _LIBCPP_STD_VER >= version should be used instead of _LIBCPP_STD_VER > prev_version +#if _LIBCPP_STD_VER > 14 +#endif + +// CHECK: warning: Use _LIBCPP_STD_VER instead of __cplusplus to constrain based on the C++ version +#if __cplusplus >= 201103L +#endif + +// CHECK: warning: _LIBCPP_STD_VER >= 11 is always true. Did you mean '#ifndef _LIBCPP_CXX03_LANG'? +#if _LIBCPP_STD_VER >= 11 +#endif + +// CHECK: warning: Not a valid value for _LIBCPP_STD_VER. Use 14, 17, 20, 23, or 26 +#if _LIBCPP_STD_VER >= 12 +#endif diff --git a/libcxx/test/libcxx/utilities/utility/unreachable.codegen.sh.cpp b/libcxx/test/libcxx/utilities/utility/unreachable.codegen.sh.cpp new file mode 100644 index 00000000000000..a93f792e756689 --- /dev/null +++ b/libcxx/test/libcxx/utilities/utility/unreachable.codegen.sh.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// This test is checking the LLVM IR +// REQUIRES: clang + +// UNSUPPORTED: asan, tsan, ubsan, msan + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// RUN: %{cxx} %s %{flags} %{compile_flags} -Wno-missing-noreturn -O3 -c -S -emit-llvm -o - | %{check-output} + +#include + +void test() { + // CHECK: define dso_local void + // CHECK-SAME: test + // CHECK-NEXT: unreachable + // CHECK-NEXT: } + std::unreachable(); +} diff --git a/libcxx/test/tools/CMakeLists.txt b/libcxx/test/tools/CMakeLists.txt index 6d99c53ad46d9f..d1d7442e99d004 100644 --- a/libcxx/test/tools/CMakeLists.txt +++ b/libcxx/test/tools/CMakeLists.txt @@ -3,6 +3,8 @@ set(LIBCXX_TEST_TOOLS_PATH ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") message(STATUS "Clang-tidy tests are disabled due to non-clang based compiler.") - return() +else() + add_subdirectory(clang_tidy_checks) endif() -add_subdirectory(clang_tidy_checks) + +add_subdirectory(check_output) diff --git a/libcxx/test/tools/check_output/CMakeLists.txt b/libcxx/test/tools/check_output/CMakeLists.txt new file mode 100644 index 00000000000000..3dd3feee298e66 --- /dev/null +++ b/libcxx/test/tools/check_output/CMakeLists.txt @@ -0,0 +1,15 @@ + +add_executable(check_output check_output.cpp) + +# put the binary into /bin +set_target_properties(check_output PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${LIBCXX_BINARY_DIR}/bin") + +# set the language mode +set_target_properties(check_output PROPERTIES + CXX_STANDARD 23 + CXX_STANDARD_REQUIRED YES + CXX_EXTENSIONS NO) + +target_compile_options(check_output PRIVATE -Werror=missing-prototypes) + +add_dependencies(cxx-test-depends check_output) diff --git a/libcxx/test/tools/check_output/check_output.cpp b/libcxx/test/tools/check_output/check_output.cpp new file mode 100644 index 00000000000000..94a84a9e40290b --- /dev/null +++ b/libcxx/test/tools/check_output/check_output.cpp @@ -0,0 +1,129 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include +#include + +using namespace std::string_view_literals; + +enum class Result { + success, + mismatch, + no_match_found, + unknown_matcher, + invalid_use, +}; + +namespace co { +namespace { +[[noreturn]] void exit(Result result) { std::exit(static_cast(result)); } + +[[noreturn]] void print_failure(int line, std::string_view stdin_content, std::string_view matcher) { + std::cout << "Failed to match: `" << matcher << "`\nRemaining data:\n" << stdin_content << '\n'; + co::exit(Result::mismatch); +} + +bool is_newline(char c) { return c == '\n'; } + +bool isblank(char c) { return std::isblank(c); } + +bool consume_front(std::string_view& sv, std::string_view start) { + if (!sv.starts_with(start)) + return false; + sv.remove_prefix(start.size()); + return true; +} +} // namespace +} // namespace co + +int main(int argc, char** argv) { + if (argc != 2) { + std::cerr << "check_output has to be used as ` | ./check_output %s`\n"; + co::exit(Result::invalid_use); + } + + std::string file_content_data = [&] { + std::ifstream file(argv[1]); + if (!file) { + std::cerr << "Failed to open file: " << argv[1] << '\n'; + co::exit(Result::invalid_use); + } + return std::string{std::istreambuf_iterator{file}, {}}; + }(); + std::string_view file_content = file_content_data; // Don't copy the data around all the time + + std::string stdin_content_data = [&] { + std::cin >> std::noskipws; + return std::string{std::istream_iterator{std::cin}, {}}; + }(); + std::string_view stdin_content = stdin_content_data; // Don't copy the data around all the time + + size_t match_count = 0; + auto drop_blanks = std::views::drop_while(co::isblank); + + while (!file_content.empty()) { + auto marker = std::ranges::search(file_content, "// CHECK"sv); + if (marker.empty()) { + if (match_count == 0) { + std::cerr << "No matcher found!\n"; + co::exit(Result::no_match_found); + } + co::exit(Result::success); + } + file_content.remove_prefix(marker.end() - file_content.begin()); + + const auto get_match = [&]() { + return std::string_view(file_content.begin(), std::ranges::find(file_content, '\n')); + }; + + if (co::consume_front(file_content, ":")) { + auto match = get_match(); + auto found = std::ranges::search( + stdin_content | std::views::drop_while(std::not_fn(co::is_newline)) | std::views::drop(1), + match | drop_blanks); + if (found.empty()) { + co::print_failure(1, stdin_content, match); + } + ++match_count; + stdin_content.remove_prefix(found.end() - stdin_content.begin()); + } else if (co::consume_front(file_content, "-SAME:")) { + auto match = get_match(); + auto haystack = std::string_view(stdin_content.begin(), std::ranges::find(stdin_content, '\n')); + auto found = std::ranges::search(haystack, match | drop_blanks); + if (found.empty()) { + co::print_failure(1, stdin_content, match); + } + stdin_content.remove_prefix(found.end() - stdin_content.begin()); + } else if (co::consume_front(file_content, "-NEXT:")) { + auto match = get_match(); + auto haystack = [&] { + auto begin = std::ranges::find(stdin_content, '\n'); + if (begin == stdin_content.end()) { + co::print_failure(1, stdin_content, match); + } + ++begin; + return std::string_view(begin, std::ranges::find(begin, stdin_content.end(), '\n')); + }(); + auto found = std::ranges::search(haystack, match | drop_blanks); + if (found.empty()) + co::print_failure(1, stdin_content, match); + stdin_content.remove_prefix(found.end() - stdin_content.begin()); + } else { + std::cerr << "Unkown matcher type " + << std::string_view(file_content.begin(), std::ranges::find(file_content, ':')) << " found\n"; + co::exit(Result::unknown_matcher); + } + } + + co::exit(Result::success); +} diff --git a/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp b/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp index ebd0d8892fa94c..44493824944b04 100644 --- a/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp +++ b/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp @@ -36,8 +36,6 @@ class proper_version_checks_callbacks : public clang::PPCallbacks { clang::CharSourceRange::getTokenRange(condition_range), preprocessor_.getSourceManager(), preprocessor_.getLangOpts()); - if (preprocessor_.getSourceManager().isInMainFile(location)) - return; if (condition == "__cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)") return; From libcxx-commits at lists.llvm.org Tue Feb 4 08:12:32 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Tue, 04 Feb 2025 08:12:32 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Decrease instantiation cost of __constexpr_memmove (PR #125109) In-Reply-To: Message-ID: <67a23c70.050a0220.a2534.2acf@mx.google.com> philnik777 wrote: > Thanks, LGTM! > > Just curious, do you have any numbers on the compilation performance improvement? IIRC for every instantiation where the condition is true you save ~0.8ms. Not huge on its own, but given that it's instantiated quite a bit it's probably a nice improvement across an entire code base. > FYI I fixed a minor typo in `never` in the commit message. Thanks! https://github.com/llvm/llvm-project/pull/125109 From libcxx-commits at lists.llvm.org Tue Feb 4 08:12:38 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Tue, 04 Feb 2025 08:12:38 -0800 (PST) Subject: [libcxx-commits] [libcxx] d814824 - [libc++] Decrease instantiation cost of __constexpr_memmove (#125109) Message-ID: <67a23c76.170a0220.3ad322.cfa3@mx.google.com> Author: Nikolas Klauser Date: 2025-02-04T17:12:35+01:00 New Revision: d8148244e9be9d4c7b12abbdbf275d80d5ba57a5 URL: https://github.com/llvm/llvm-project/commit/d8148244e9be9d4c7b12abbdbf275d80d5ba57a5 DIFF: https://github.com/llvm/llvm-project/commit/d8148244e9be9d4c7b12abbdbf275d80d5ba57a5.diff LOG: [libc++] Decrease instantiation cost of __constexpr_memmove (#125109) Using `if constexpr` in `__constexpr_memmove` makes the instantiation three times faster for the same type, since it avoids a bunch of class instantiations and SFINAE for constexpr support that's never actually used. Given that `__constexpr_memmove` is used quite a bit through `std::copy` and is instantiated multiple times when just including `<__string/char_traits.h>` this can provide a nice compile time speedup for a very simple change. Added: Modified: libcxx/include/__string/constexpr_c_functions.h Removed: ################################################################################ diff --git a/libcxx/include/__string/constexpr_c_functions.h b/libcxx/include/__string/constexpr_c_functions.h index 0bc128b68b5799..fbe7e10d440ce1 100644 --- a/libcxx/include/__string/constexpr_c_functions.h +++ b/libcxx/include/__string/constexpr_c_functions.h @@ -204,23 +204,26 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& __assign_trivially_copy return __dest; } -template ::value, int> = 0> +template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __constexpr_memmove(_Tp* __dest, _Up* __src, __element_count __n) { + static_assert(__is_always_bitcastable<_Up, _Tp>::value); size_t __count = static_cast(__n); if (__libcpp_is_constant_evaluated()) { #ifdef _LIBCPP_COMPILER_CLANG_BASED - if (is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value) { + if _LIBCPP_CONSTEXPR (is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value) { ::__builtin_memmove(__dest, __src, __count * sizeof(_Tp)); return __dest; - } + } else #endif - if (std::__is_pointer_in_range(__src, __src + __count, __dest)) { - for (; __count > 0; --__count) - std::__assign_trivially_copyable(__dest[__count - 1], __src[__count - 1]); - } else { - for (size_t __i = 0; __i != __count; ++__i) - std::__assign_trivially_copyable(__dest[__i], __src[__i]); + { + if (std::__is_pointer_in_range(__src, __src + __count, __dest)) { + for (; __count > 0; --__count) + std::__assign_trivially_copyable(__dest[__count - 1], __src[__count - 1]); + } else { + for (size_t __i = 0; __i != __count; ++__i) + std::__assign_trivially_copyable(__dest[__i], __src[__i]); + } } } else if (__count > 0) { ::__builtin_memmove(__dest, __src, (__count - 1) * sizeof(_Tp) + __datasizeof_v<_Tp>); From libcxx-commits at lists.llvm.org Tue Feb 4 08:12:42 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Tue, 04 Feb 2025 08:12:42 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Decrease instantiation cost of __constexpr_memmove (PR #125109) In-Reply-To: Message-ID: <67a23c7a.170a0220.10d14.cbf3@mx.google.com> https://github.com/philnik777 closed https://github.com/llvm/llvm-project/pull/125109 From libcxx-commits at lists.llvm.org Tue Feb 4 08:26:01 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Tue, 04 Feb 2025 08:26:01 -0800 (PST) Subject: [libcxx-commits] [libcxx] [lib++][Format] Updates Unicode database. (PR #125712) Message-ID: https://github.com/mordante created https://github.com/llvm/llvm-project/pull/125712 Updates the databease to the Unicode release 16.0.0. The algorithms of the Grapheme clustering rules have not changed. >From 9e2d61b91d3d04094e3a4b0bf68ce6e0d15283e0 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Mon, 3 Feb 2025 22:51:36 +0100 Subject: [PATCH] [lib++][Format] Updates Unicode database. Updates the databease to the Unicode release 16.0.0. The algorithms of the Grapheme clustering rules have not changed. --- libcxx/docs/ReleaseNotes/21.rst | 1 + .../include/__format/escaped_output_table.h | 82 +- .../extended_grapheme_cluster_table.h | 99 +- .../__format/indic_conjunct_break_table.h | 312 +++- .../include/__format/width_estimation_table.h | 19 +- .../extended_grapheme_cluster.h | 1344 +++++++---------- .../data/unicode/DerivedCoreProperties.txt | 834 ++++++++-- .../data/unicode/DerivedGeneralCategory.txt | 206 ++- libcxx/utils/data/unicode/EastAsianWidth.txt | 115 +- .../data/unicode/GraphemeBreakProperty.txt | 96 +- .../utils/data/unicode/GraphemeBreakTest.txt | 464 +++--- libcxx/utils/data/unicode/emoji-data.txt | 42 +- 12 files changed, 2103 insertions(+), 1511 deletions(-) diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad3942..24393607970238 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -46,6 +46,7 @@ Improvements and New Features - The ``std::ranges::{copy, copy_n, copy_backward}`` algorithms have been optimized for ``std::vector::iterator``\s, resulting in a performance improvement of up to 2000x. +- Updated formatting library to Unicode 16.0.0. Deprecations and Removals ------------------------- diff --git a/libcxx/include/__format/escaped_output_table.h b/libcxx/include/__format/escaped_output_table.h index 7a0b35239861e0..1401b4637d8396 100644 --- a/libcxx/include/__format/escaped_output_table.h +++ b/libcxx/include/__format/escaped_output_table.h @@ -109,7 +109,7 @@ namespace __escaped_output_table { /// - bits [14, 31] The lower bound code point of the range. The upper bound of /// the range is lower bound + size. Note the code expects code units the fit /// into 18 bits, instead of the 21 bits needed for the full Unicode range. -_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[735] = { 0x00000020 /* 00000000 - 00000020 [ 33] */, 0x001fc021 /* 0000007f - 000000a0 [ 34] */, 0x002b4000 /* 000000ad - 000000ad [ 1] */, @@ -136,7 +136,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x02170001 /* 0000085c - 0000085d [ 2] */, 0x0217c000 /* 0000085f - 0000085f [ 1] */, 0x021ac004 /* 0000086b - 0000086f [ 5] */, - 0x0223c008 /* 0000088f - 00000897 [ 9] */, + 0x0223c007 /* 0000088f - 00000896 [ 8] */, 0x02388000 /* 000008e2 - 000008e2 [ 1] */, 0x02610000 /* 00000984 - 00000984 [ 1] */, 0x02634001 /* 0000098d - 0000098e [ 2] */, @@ -331,12 +331,11 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x06a68005 /* 00001a9a - 00001a9f [ 6] */, 0x06ab8001 /* 00001aae - 00001aaf [ 2] */, 0x06b3c030 /* 00001acf - 00001aff [ 49] */, - 0x06d34002 /* 00001b4d - 00001b4f [ 3] */, - 0x06dfc000 /* 00001b7f - 00001b7f [ 1] */, + 0x06d34000 /* 00001b4d - 00001b4d [ 1] */, 0x06fd0007 /* 00001bf4 - 00001bfb [ 8] */, 0x070e0002 /* 00001c38 - 00001c3a [ 3] */, 0x07128002 /* 00001c4a - 00001c4c [ 3] */, - 0x07224006 /* 00001c89 - 00001c8f [ 7] */, + 0x0722c004 /* 00001c8b - 00001c8f [ 5] */, 0x072ec001 /* 00001cbb - 00001cbc [ 2] */, 0x07320007 /* 00001cc8 - 00001ccf [ 8] */, 0x073ec004 /* 00001cfb - 00001cff [ 5] */, @@ -364,7 +363,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x0830400e /* 000020c1 - 000020cf [ 15] */, 0x083c400e /* 000020f1 - 000020ff [ 15] */, 0x08630003 /* 0000218c - 0000218f [ 4] */, - 0x0909c018 /* 00002427 - 0000243f [ 25] */, + 0x090a8015 /* 0000242a - 0000243f [ 22] */, 0x0912c014 /* 0000244b - 0000245f [ 21] */, 0x0add0001 /* 00002b74 - 00002b75 [ 2] */, 0x0ae58000 /* 00002b96 - 00002b96 [ 1] */, @@ -393,16 +392,16 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x0c400004 /* 00003100 - 00003104 [ 5] */, 0x0c4c0000 /* 00003130 - 00003130 [ 1] */, 0x0c63c000 /* 0000318f - 0000318f [ 1] */, - 0x0c79000a /* 000031e4 - 000031ee [ 11] */, + 0x0c798008 /* 000031e6 - 000031ee [ 9] */, 0x0c87c000 /* 0000321f - 0000321f [ 1] */, 0x29234002 /* 0000a48d - 0000a48f [ 3] */, 0x2931c008 /* 0000a4c7 - 0000a4cf [ 9] */, 0x298b0013 /* 0000a62c - 0000a63f [ 20] */, 0x29be0007 /* 0000a6f8 - 0000a6ff [ 8] */, - 0x29f2c004 /* 0000a7cb - 0000a7cf [ 5] */, + 0x29f38001 /* 0000a7ce - 0000a7cf [ 2] */, 0x29f48000 /* 0000a7d2 - 0000a7d2 [ 1] */, 0x29f50000 /* 0000a7d4 - 0000a7d4 [ 1] */, - 0x29f68017 /* 0000a7da - 0000a7f1 [ 24] */, + 0x29f74014 /* 0000a7dd - 0000a7f1 [ 21] */, 0x2a0b4002 /* 0000a82d - 0000a82f [ 3] */, 0x2a0e8005 /* 0000a83a - 0000a83f [ 6] */, 0x2a1e0007 /* 0000a878 - 0000a87f [ 8] */, @@ -491,7 +490,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x41688000 /* 000105a2 - 000105a2 [ 1] */, 0x416c8000 /* 000105b2 - 000105b2 [ 1] */, 0x416e8000 /* 000105ba - 000105ba [ 1] */, - 0x416f4042 /* 000105bd - 000105ff [ 67] */, + 0x416f4002 /* 000105bd - 000105bf [ 3] */, + 0x417d000b /* 000105f4 - 000105ff [ 12] */, 0x41cdc008 /* 00010737 - 0001073f [ 9] */, 0x41d58009 /* 00010756 - 0001075f [ 10] */, 0x41da0017 /* 00010768 - 0001077f [ 24] */, @@ -534,11 +534,15 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x432cc00c /* 00010cb3 - 00010cbf [ 13] */, 0x433cc006 /* 00010cf3 - 00010cf9 [ 7] */, 0x434a0007 /* 00010d28 - 00010d2f [ 8] */, - 0x434e8125 /* 00010d3a - 00010e5f [ 294] */, + 0x434e8005 /* 00010d3a - 00010d3f [ 6] */, + 0x43598002 /* 00010d66 - 00010d68 [ 3] */, + 0x43618007 /* 00010d86 - 00010d8d [ 8] */, + 0x436400cf /* 00010d90 - 00010e5f [ 208] */, 0x439fc000 /* 00010e7f - 00010e7f [ 1] */, 0x43aa8000 /* 00010eaa - 00010eaa [ 1] */, 0x43ab8001 /* 00010eae - 00010eaf [ 2] */, - 0x43ac804a /* 00010eb2 - 00010efc [ 75] */, + 0x43ac800f /* 00010eb2 - 00010ec1 [ 16] */, + 0x43b14036 /* 00010ec5 - 00010efb [ 55] */, 0x43ca0007 /* 00010f28 - 00010f2f [ 8] */, 0x43d68015 /* 00010f5a - 00010f6f [ 22] */, 0x43e28025 /* 00010f8a - 00010faf [ 38] */, @@ -578,7 +582,18 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x44d60004 /* 00011358 - 0001135c [ 5] */, 0x44d90001 /* 00011364 - 00011365 [ 2] */, 0x44db4002 /* 0001136d - 0001136f [ 3] */, - 0x44dd408a /* 00011375 - 000113ff [ 139] */, + 0x44dd400a /* 00011375 - 0001137f [ 11] */, + 0x44e28000 /* 0001138a - 0001138a [ 1] */, + 0x44e30001 /* 0001138c - 0001138d [ 2] */, + 0x44e3c000 /* 0001138f - 0001138f [ 1] */, + 0x44ed8000 /* 000113b6 - 000113b6 [ 1] */, + 0x44f04000 /* 000113c1 - 000113c1 [ 1] */, + 0x44f0c001 /* 000113c3 - 000113c4 [ 2] */, + 0x44f18000 /* 000113c6 - 000113c6 [ 1] */, + 0x44f2c000 /* 000113cb - 000113cb [ 1] */, + 0x44f58000 /* 000113d6 - 000113d6 [ 1] */, + 0x44f64007 /* 000113d9 - 000113e0 [ 8] */, + 0x44f8c01c /* 000113e3 - 000113ff [ 29] */, 0x45170000 /* 0001145c - 0001145c [ 1] */, 0x4518801d /* 00011462 - 0001147f [ 30] */, 0x45320007 /* 000114c8 - 000114cf [ 8] */, @@ -589,7 +604,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x45968005 /* 0001165a - 0001165f [ 6] */, 0x459b4012 /* 0001166d - 0001167f [ 19] */, 0x45ae8005 /* 000116ba - 000116bf [ 6] */, - 0x45b28035 /* 000116ca - 000116ff [ 54] */, + 0x45b28005 /* 000116ca - 000116cf [ 6] */, + 0x45b9001b /* 000116e4 - 000116ff [ 28] */, 0x45c6c001 /* 0001171b - 0001171c [ 2] */, 0x45cb0003 /* 0001172c - 0001172f [ 4] */, 0x45d1c0b8 /* 00011747 - 000117ff [ 185] */, @@ -609,7 +625,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x46920007 /* 00011a48 - 00011a4f [ 8] */, 0x46a8c00c /* 00011aa3 - 00011aaf [ 13] */, 0x46be4006 /* 00011af9 - 00011aff [ 7] */, - 0x46c280f5 /* 00011b0a - 00011bff [ 246] */, + 0x46c280b5 /* 00011b0a - 00011bbf [ 182] */, + 0x46f8800d /* 00011be2 - 00011bef [ 14] */, + 0x46fe8005 /* 00011bfa - 00011bff [ 6] */, 0x47024000 /* 00011c09 - 00011c09 [ 1] */, 0x470dc000 /* 00011c37 - 00011c37 [ 1] */, 0x47118009 /* 00011c46 - 00011c4f [ 10] */, @@ -633,7 +651,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x47be4006 /* 00011ef9 - 00011eff [ 7] */, 0x47c44000 /* 00011f11 - 00011f11 [ 1] */, 0x47cec002 /* 00011f3b - 00011f3d [ 3] */, - 0x47d68055 /* 00011f5a - 00011faf [ 86] */, + 0x47d6c054 /* 00011f5b - 00011faf [ 85] */, 0x47ec400e /* 00011fb1 - 00011fbf [ 15] */, 0x47fc800c /* 00011ff2 - 00011ffe [ 13] */, 0x48e68065 /* 0001239a - 000123ff [ 102] */, @@ -642,8 +660,10 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x49510a4b /* 00012544 - 00012f8f [ 2636] */, 0x4bfcc00c /* 00012ff3 - 00012fff [ 13] */, 0x4d0c000f /* 00013430 - 0001343f [ 16] */, - 0x4d158fa9 /* 00013456 - 000143ff [ 4010] */, - 0x5191e1b8 /* 00014647 - 000167ff [ 8633] */, + 0x4d158009 /* 00013456 - 0001345f [ 10] */, + 0x50fec004 /* 000143fb - 000143ff [ 5] */, + 0x5191dab8 /* 00014647 - 000160ff [ 6841] */, + 0x584e86c5 /* 0001613a - 000167ff [ 1734] */, 0x5a8e4006 /* 00016a39 - 00016a3f [ 7] */, 0x5a97c000 /* 00016a5f - 00016a5f [ 1] */, 0x5a9a8003 /* 00016a6a - 00016a6d [ 4] */, @@ -655,7 +675,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x5ad68000 /* 00016b5a - 00016b5a [ 1] */, 0x5ad88000 /* 00016b62 - 00016b62 [ 1] */, 0x5ade0004 /* 00016b78 - 00016b7c [ 5] */, - 0x5ae402af /* 00016b90 - 00016e3f [ 688] */, + 0x5ae401af /* 00016b90 - 00016d3f [ 432] */, + 0x5b5e80c5 /* 00016d7a - 00016e3f [ 198] */, 0x5ba6c064 /* 00016e9b - 00016eff [ 101] */, 0x5bd2c003 /* 00016f4b - 00016f4e [ 4] */, 0x5be20006 /* 00016f88 - 00016f8e [ 7] */, @@ -663,7 +684,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x5bf9400a /* 00016fe5 - 00016fef [ 11] */, 0x5bfc800d /* 00016ff2 - 00016fff [ 14] */, 0x61fe0007 /* 000187f8 - 000187ff [ 8] */, - 0x63358029 /* 00018cd6 - 00018cff [ 42] */, + 0x63358028 /* 00018cd6 - 00018cfe [ 41] */, 0x634262e6 /* 00018d09 - 0001afef [ 8935] */, 0x6bfd0000 /* 0001aff4 - 0001aff4 [ 1] */, 0x6bff0000 /* 0001affc - 0001affc [ 1] */, @@ -678,7 +699,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x6f1f4002 /* 0001bc7d - 0001bc7f [ 3] */, 0x6f224006 /* 0001bc89 - 0001bc8f [ 7] */, 0x6f268001 /* 0001bc9a - 0001bc9b [ 2] */, - 0x6f28125f /* 0001bca0 - 0001ceff [ 4704] */, + 0x6f280f5f /* 0001bca0 - 0001cbff [ 3936] */, + 0x733e8005 /* 0001ccfa - 0001ccff [ 6] */, + 0x73ad004b /* 0001ceb4 - 0001ceff [ 76] */, 0x73cb8001 /* 0001cf2e - 0001cf2f [ 2] */, 0x73d1c008 /* 0001cf47 - 0001cf4f [ 9] */, 0x73f1003b /* 0001cfc4 - 0001cfff [ 60] */, @@ -730,7 +753,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x78abc010 /* 0001e2af - 0001e2bf [ 17] */, 0x78be8004 /* 0001e2fa - 0001e2fe [ 5] */, 0x78c001cf /* 0001e300 - 0001e4cf [ 464] */, - 0x793e82e5 /* 0001e4fa - 0001e7df [ 742] */, + 0x793e80d5 /* 0001e4fa - 0001e5cf [ 214] */, + 0x797ec003 /* 0001e5fb - 0001e5fe [ 4] */, + 0x798001df /* 0001e600 - 0001e7df [ 480] */, 0x79f9c000 /* 0001e7e7 - 0001e7e7 [ 1] */, 0x79fb0000 /* 0001e7ec - 0001e7ec [ 1] */, 0x79fbc000 /* 0001e7ef - 0001e7ef [ 1] */, @@ -800,18 +825,17 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x7e168005 /* 0001f85a - 0001f85f [ 6] */, 0x7e220007 /* 0001f888 - 0001f88f [ 8] */, 0x7e2b8001 /* 0001f8ae - 0001f8af [ 2] */, - 0x7e2c804d /* 0001f8b2 - 0001f8ff [ 78] */, + 0x7e2f0003 /* 0001f8bc - 0001f8bf [ 4] */, + 0x7e30803d /* 0001f8c2 - 0001f8ff [ 62] */, 0x7e95000b /* 0001fa54 - 0001fa5f [ 12] */, 0x7e9b8001 /* 0001fa6e - 0001fa6f [ 2] */, 0x7e9f4002 /* 0001fa7d - 0001fa7f [ 3] */, - 0x7ea24006 /* 0001fa89 - 0001fa8f [ 7] */, - 0x7eaf8000 /* 0001fabe - 0001fabe [ 1] */, - 0x7eb18007 /* 0001fac6 - 0001facd [ 8] */, - 0x7eb70003 /* 0001fadc - 0001fadf [ 4] */, - 0x7eba4006 /* 0001fae9 - 0001faef [ 7] */, + 0x7ea28004 /* 0001fa8a - 0001fa8e [ 5] */, + 0x7eb1c006 /* 0001fac7 - 0001facd [ 7] */, + 0x7eb74001 /* 0001fadd - 0001fade [ 2] */, + 0x7eba8005 /* 0001faea - 0001faef [ 6] */, 0x7ebe4006 /* 0001faf9 - 0001faff [ 7] */, 0x7ee4c000 /* 0001fb93 - 0001fb93 [ 1] */, - 0x7ef2c024 /* 0001fbcb - 0001fbef [ 37] */, 0x7efe8405 /* 0001fbfa - 0001ffff [ 1030] */, 0xa9b8001f /* 0002a6e0 - 0002a6ff [ 32] */, 0xadce8005 /* 0002b73a - 0002b73f [ 6] */, diff --git a/libcxx/include/__format/extended_grapheme_cluster_table.h b/libcxx/include/__format/extended_grapheme_cluster_table.h index 7653a9e03b815d..f76e018df7ae11 100644 --- a/libcxx/include/__format/extended_grapheme_cluster_table.h +++ b/libcxx/include/__format/extended_grapheme_cluster_table.h @@ -125,7 +125,7 @@ enum class __property : uint8_t { /// following benchmark. /// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp // clang-format off -_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1501] = { 0x00000091, 0x00005005, 0x00005811, @@ -164,7 +164,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x00414842, 0x0042c822, 0x00448018, - 0x0044c072, + 0x0044b882, 0x00465172, 0x00471008, 0x004719f2, @@ -246,14 +246,12 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0064101a, 0x0065e002, 0x0065f00a, - 0x0065f802, - 0x0066001a, + 0x0065f812, + 0x0066080a, 0x00661002, 0x0066181a, - 0x00663002, - 0x0066381a, - 0x0066501a, - 0x00666012, + 0x00663022, + 0x00665032, 0x0066a812, 0x00671012, 0x0067980a, @@ -318,10 +316,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x008b047c, 0x008d457b, 0x009ae822, - 0x00b89022, - 0x00b8a80a, - 0x00b99012, - 0x00b9a00a, + 0x00b89032, + 0x00b99022, 0x00ba9012, 0x00bb9012, 0x00bda012, @@ -361,29 +357,23 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x00d581e2, 0x00d80032, 0x00d8200a, - 0x00d9a062, - 0x00d9d80a, - 0x00d9e002, - 0x00d9e84a, - 0x00da1002, - 0x00da181a, + 0x00d9a092, + 0x00d9f03a, + 0x00da1022, 0x00db5882, 0x00dc0012, 0x00dc100a, 0x00dd080a, 0x00dd1032, 0x00dd301a, - 0x00dd4012, - 0x00dd500a, - 0x00dd5822, + 0x00dd4052, 0x00df3002, 0x00df380a, 0x00df4012, 0x00df502a, 0x00df6802, 0x00df700a, - 0x00df7822, - 0x00df901a, + 0x00df7842, 0x00e1207a, 0x00e16072, 0x00e1a01a, @@ -475,7 +465,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0547f802, 0x05493072, 0x054a38a2, - 0x054a901a, + 0x054a900a, + 0x054a9802, 0x054b01c4, 0x054c0022, 0x054c180a, @@ -484,7 +475,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x054db032, 0x054dd01a, 0x054de012, - 0x054df02a, + 0x054df01a, + 0x054e0002, 0x054f2802, 0x05514852, 0x0551781a, @@ -1328,8 +1320,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0851f802, 0x08572812, 0x08692032, + 0x086b4842, 0x08755812, - 0x0877e822, + 0x0877e032, 0x087a30a2, 0x087c1032, 0x0880000a, @@ -1357,7 +1350,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x088c100a, 0x088d982a, 0x088db082, - 0x088df81a, + 0x088df80a, + 0x088e0002, 0x088e1018, 0x088e4832, 0x088e700a, @@ -1365,9 +1359,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0891602a, 0x08917822, 0x0891901a, - 0x0891a002, - 0x0891a80a, - 0x0891b012, + 0x0891a032, 0x0891f002, 0x08920802, 0x0896f802, @@ -1381,11 +1373,24 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x089a0002, 0x089a083a, 0x089a381a, - 0x089a582a, + 0x089a581a, + 0x089a6802, 0x089ab802, 0x089b101a, 0x089b3062, 0x089b8042, + 0x089dc002, + 0x089dc81a, + 0x089dd852, + 0x089e1002, + 0x089e2802, + 0x089e3822, + 0x089e500a, + 0x089e601a, + 0x089e7022, + 0x089e8808, + 0x089e9002, + 0x089f0812, 0x08a1a82a, 0x08a1c072, 0x08a2001a, @@ -1422,10 +1427,10 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x08b5600a, 0x08b56802, 0x08b5701a, - 0x08b58052, - 0x08b5b00a, - 0x08b5b802, - 0x08b8e822, + 0x08b58072, + 0x08b8e802, + 0x08b8f00a, + 0x08b8f802, 0x08b91032, 0x08b9300a, 0x08b93842, @@ -1436,9 +1441,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x08c98002, 0x08c9884a, 0x08c9b81a, - 0x08c9d812, - 0x08c9e80a, - 0x08c9f002, + 0x08c9d832, 0x08c9f808, 0x08ca000a, 0x08ca0808, @@ -1495,28 +1498,29 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x08f9a01a, 0x08f9b042, 0x08f9f01a, - 0x08fa0002, - 0x08fa080a, - 0x08fa1002, + 0x08fa0022, + 0x08fad002, 0x09a180f1, 0x09a20002, 0x09a238e2, + 0x0b08f0b2, + 0x0b09502a, + 0x0b096822, 0x0b578042, 0x0b598062, + 0x0b6b180c, + 0x0b6b383c, 0x0b7a7802, 0x0b7a8b6a, 0x0b7c7832, 0x0b7f2002, - 0x0b7f801a, + 0x0b7f8012, 0x0de4e812, 0x0de50031, 0x0e7802d2, 0x0e798162, - 0x0e8b2802, - 0x0e8b300a, - 0x0e8b3822, - 0x0e8b680a, - 0x0e8b7042, + 0x0e8b2842, + 0x0e8b6852, 0x0e8b9871, 0x0e8bd872, 0x0e8c2862, @@ -1538,6 +1542,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0f157002, 0x0f176032, 0x0f276032, + 0x0f2f7012, 0x0f468062, 0x0f4a2062, 0x0f8007f3, diff --git a/libcxx/include/__format/indic_conjunct_break_table.h b/libcxx/include/__format/indic_conjunct_break_table.h index df6cfe6a02f348..f48ea625908e99 100644 --- a/libcxx/include/__format/indic_conjunct_break_table.h +++ b/libcxx/include/__format/indic_conjunct_break_table.h @@ -107,10 +107,9 @@ enum class __property : uint8_t { /// following benchmark. /// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp // clang-format off -_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { - 0x00180139, - 0x001a807d, - 0x00241811, +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[403] = { + 0x001801bd, + 0x00241819, 0x002c88b1, 0x002df801, 0x002e0805, @@ -125,6 +124,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { 0x0037500d, 0x00388801, 0x00398069, + 0x003d3029, 0x003f5821, 0x003fe801, 0x0040b00d, @@ -132,87 +132,174 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { 0x00412809, 0x00414811, 0x0042c809, - 0x0044c01d, + 0x0044b821, 0x0046505d, - 0x00471871, + 0x0047187d, 0x0048a890, + 0x0049d001, 0x0049e001, + 0x004a081d, 0x004a6802, - 0x004a880d, + 0x004a8819, 0x004ac01c, + 0x004b1005, 0x004bc01c, + 0x004c0801, 0x004ca84c, 0x004d5018, 0x004d9000, 0x004db00c, 0x004de001, + 0x004df001, + 0x004e080d, 0x004e6802, + 0x004eb801, 0x004ee004, 0x004ef800, + 0x004f1005, 0x004f8004, 0x004ff001, + 0x00500805, 0x0051e001, + 0x00520805, + 0x00523805, + 0x00525809, + 0x00528801, + 0x00538005, + 0x0053a801, + 0x00540805, 0x0054a84c, 0x00555018, 0x00559004, 0x0055a810, 0x0055e001, + 0x00560811, + 0x00563805, 0x00566802, + 0x00571005, 0x0057c800, + 0x0057d015, + 0x00580801, 0x0058a84c, 0x00595018, 0x00599004, 0x0059a810, 0x0059e001, + 0x0059f005, + 0x005a080d, 0x005a6802, + 0x005aa809, 0x005ae004, 0x005af800, + 0x005b1005, 0x005b8800, + 0x005c1001, + 0x005df001, + 0x005e0001, + 0x005e6801, + 0x005eb801, + 0x00600001, + 0x00602001, 0x0060a84c, 0x0061503c, 0x0061e001, + 0x0061f009, + 0x00623009, + 0x00625009, 0x00626802, 0x0062a805, 0x0062c008, + 0x00631005, + 0x00640801, 0x0065e001, + 0x0065f805, + 0x00661001, + 0x00663009, + 0x0066500d, + 0x0066a805, + 0x00671005, + 0x00680005, 0x0068a894, 0x0069d805, + 0x0069f001, + 0x006a080d, 0x006a6802, - 0x0071c009, - 0x0072400d, - 0x0075c009, - 0x0076400d, + 0x006ab801, + 0x006b1005, + 0x006c0801, + 0x006e5001, + 0x006e7801, + 0x006e9009, + 0x006eb001, + 0x006ef801, + 0x00718801, + 0x0071a019, + 0x0072381d, + 0x00758801, + 0x0075a021, + 0x00764019, 0x0078c005, 0x0079a801, 0x0079b801, 0x0079c801, - 0x007b8805, - 0x007ba001, - 0x007bd00d, - 0x007c0001, - 0x007c1009, + 0x007b8835, + 0x007c0011, 0x007c3005, + 0x007c6829, + 0x007cc88d, 0x007e3001, - 0x0081b801, + 0x0081680d, + 0x00819015, 0x0081c805, + 0x0081e805, + 0x0082c005, + 0x0082f009, + 0x0083880d, + 0x00841001, + 0x00842805, 0x00846801, + 0x0084e801, 0x009ae809, - 0x00b8a001, - 0x00be9001, + 0x00b8900d, + 0x00b99009, + 0x00ba9005, + 0x00bb9005, + 0x00bda005, + 0x00bdb819, + 0x00be3001, + 0x00be4829, 0x00bee801, + 0x00c05809, + 0x00c07801, + 0x00c42805, 0x00c54801, + 0x00c90009, + 0x00c93805, + 0x00c99001, 0x00c9c809, 0x00d0b805, + 0x00d0d801, + 0x00d2b001, + 0x00d2c019, 0x00d30001, - 0x00d3a81d, + 0x00d31001, + 0x00d3281d, + 0x00d39825, 0x00d3f801, - 0x00d58035, - 0x00d5f83d, - 0x00d9a001, + 0x00d58079, + 0x00d8000d, + 0x00d9a025, + 0x00da1009, 0x00db5821, - 0x00dd5801, + 0x00dc0005, + 0x00dd100d, + 0x00dd4015, 0x00df3001, - 0x00e1b801, + 0x00df4005, + 0x00df6801, + 0x00df7811, + 0x00e1601d, + 0x00e1b005, 0x00e68009, 0x00e6a031, 0x00e71019, @@ -221,82 +308,193 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { 0x00e7c005, 0x00ee00fd, 0x01006801, - 0x01068031, - 0x01070801, - 0x0107282d, + 0x01068081, 0x01677809, 0x016bf801, 0x016f007d, 0x01815015, 0x0184c805, - 0x05337801, + 0x0533780d, 0x0533a025, 0x0534f005, 0x05378005, + 0x05401001, + 0x05403001, + 0x05405801, + 0x05412805, 0x05416001, + 0x05462005, 0x05470045, - 0x05495809, + 0x0547f801, + 0x0549301d, + 0x054a3829, + 0x054a9801, + 0x054c0009, 0x054d9801, + 0x054db00d, + 0x054de005, + 0x054e0001, + 0x054f2801, + 0x05514815, + 0x05518805, + 0x0551a805, + 0x05521801, + 0x05526001, + 0x0553e001, 0x05558001, 0x05559009, 0x0555b805, 0x0555f005, 0x05560801, + 0x05576005, 0x0557b001, + 0x055f2801, + 0x055f4001, 0x055f6801, 0x07d8f001, + 0x07f0003d, 0x07f1003d, + 0x07fcf005, 0x080fe801, 0x08170001, 0x081bb011, - 0x08506801, - 0x08507801, + 0x08500809, + 0x08502805, + 0x0850600d, 0x0851c009, 0x0851f801, 0x08572805, 0x0869200d, + 0x086b4811, 0x08755805, - 0x0877e809, + 0x0877e00d, 0x087a3029, 0x087c100d, + 0x08800801, + 0x0881c039, 0x08838001, - 0x0883f801, - 0x0885d001, + 0x08839805, + 0x0883f809, + 0x0885980d, + 0x0885c805, + 0x08861001, 0x08880009, - 0x08899805, + 0x08893811, + 0x0889681d, 0x088b9801, - 0x088e5001, - 0x0891b001, - 0x08974805, + 0x088c0005, + 0x088db021, + 0x088e0001, + 0x088e480d, + 0x088e7801, + 0x08917809, + 0x0891a00d, + 0x0891f001, + 0x08920801, + 0x0896f801, + 0x0897181d, + 0x08980005, 0x0899d805, + 0x0899f001, + 0x089a0001, + 0x089a6801, + 0x089ab801, 0x089b3019, 0x089b8011, + 0x089dc001, + 0x089dd815, + 0x089e1001, + 0x089e2801, + 0x089e3809, + 0x089e7009, + 0x089e9001, + 0x089f0805, + 0x08a1c01d, + 0x08a21009, 0x08a23001, 0x08a2f001, - 0x08a61801, - 0x08ae0001, - 0x08b5b801, - 0x08b95801, - 0x08c1d001, - 0x08c9f001, + 0x08a58001, + 0x08a59815, + 0x08a5d001, + 0x08a5e801, + 0x08a5f805, + 0x08a61005, + 0x08ad7801, + 0x08ad900d, + 0x08ade005, + 0x08adf805, + 0x08aee005, + 0x08b1981d, + 0x08b1e801, + 0x08b1f805, + 0x08b55801, + 0x08b56801, + 0x08b5801d, + 0x08b8e801, + 0x08b8f801, + 0x08b9100d, + 0x08b93811, + 0x08c17821, + 0x08c1c805, + 0x08c98001, + 0x08c9d80d, 0x08ca1801, - 0x08d1a001, + 0x08cea00d, + 0x08ced005, + 0x08cf0001, + 0x08d00825, + 0x08d19815, + 0x08d1d80d, 0x08d23801, - 0x08d4c801, - 0x08ea1001, - 0x08ea2005, + 0x08d28815, + 0x08d2c809, + 0x08d45031, + 0x08d4c005, + 0x08e18019, + 0x08e1c015, + 0x08e1f801, + 0x08e49055, + 0x08e55019, + 0x08e59005, + 0x08e5a805, + 0x08e98815, + 0x08e9d001, + 0x08e9e005, + 0x08e9f819, + 0x08ea3801, + 0x08ec8005, + 0x08eca801, 0x08ecb801, - 0x08fa1001, + 0x08f79805, + 0x08f80005, + 0x08f9b011, + 0x08fa0009, + 0x08fad001, + 0x09a20001, + 0x09a23839, + 0x0b08f02d, + 0x0b096809, 0x0b578011, 0x0b598019, - 0x0de4f001, - 0x0e8b2801, - 0x0e8b3809, - 0x0e8b7011, + 0x0b7a7801, + 0x0b7c780d, + 0x0b7f2001, + 0x0b7f8005, + 0x0de4e805, + 0x0e7800b5, + 0x0e798059, + 0x0e8b2811, + 0x0e8b6815, 0x0e8bd81d, 0x0e8c2819, 0x0e8d500d, 0x0e921009, + 0x0ed000d9, + 0x0ed1d8c5, + 0x0ed3a801, + 0x0ed42001, + 0x0ed4d811, + 0x0ed50839, 0x0f000019, 0x0f004041, 0x0f00d819, @@ -307,8 +505,12 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { 0x0f157001, 0x0f17600d, 0x0f27600d, + 0x0f2f7005, 0x0f468019, - 0x0f4a2019}; + 0x0f4a2019, + 0x0f9fd811, + 0x7001017d, + 0x700803bd}; // clang-format on /// Returns the indic conjuct break property of a code point. diff --git a/libcxx/include/__format/width_estimation_table.h b/libcxx/include/__format/width_estimation_table.h index 5b4b3950c6a1d0..0ea0b4f413a748 100644 --- a/libcxx/include/__format/width_estimation_table.h +++ b/libcxx/include/__format/width_estimation_table.h @@ -119,7 +119,7 @@ namespace __width_estimation_table { /// - bits [0, 13] The size of the range, allowing 16384 elements. /// - bits [14, 31] The lower bound code point of the range. The upper bound of /// the range is lower bound + size. -_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[110] = { 0x0440005f /* 00001100 - 0000115f [ 96] */, // 0x08c68001 /* 0000231a - 0000231b [ 2] */, // 0x08ca4001 /* 00002329 - 0000232a [ 2] */, // @@ -128,8 +128,10 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { 0x08fcc000 /* 000023f3 - 000023f3 [ 1] */, // 0x097f4001 /* 000025fd - 000025fe [ 2] */, // 0x09850001 /* 00002614 - 00002615 [ 2] */, // + 0x098c0007 /* 00002630 - 00002637 [ 8] */, // 0x0992000b /* 00002648 - 00002653 [ 12] */, // 0x099fc000 /* 0000267f - 0000267f [ 1] */, // + 0x09a28005 /* 0000268a - 0000268f [ 6] */, // 0x09a4c000 /* 00002693 - 00002693 [ 1] */, // 0x09a84000 /* 000026a1 - 000026a1 [ 1] */, // 0x09aa8001 /* 000026aa - 000026ab [ 2] */, // @@ -163,7 +165,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { 0x0c264066 /* 00003099 - 000030ff [ 103] */, // 0x0c41402a /* 00003105 - 0000312f [ 43] */, // 0x0c4c405d /* 00003131 - 0000318e [ 94] */, // - 0x0c640053 /* 00003190 - 000031e3 [ 84] */, // + 0x0c640055 /* 00003190 - 000031e5 [ 86] */, // 0x0c7bc02f /* 000031ef - 0000321e [ 48] */, // 0x0c880027 /* 00003220 - 00003247 [ 40] */, // 0x0c943fff /* 00003250 - 0000724f [16384] */, // @@ -182,7 +184,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { 0x5bfc0001 /* 00016ff0 - 00016ff1 [ 2] */, // 0x5c0017f7 /* 00017000 - 000187f7 [ 6136] */, // 0x620004d5 /* 00018800 - 00018cd5 [ 1238] */, // - 0x63400008 /* 00018d00 - 00018d08 [ 9] */, // + 0x633fc009 /* 00018cff - 00018d08 [ 10] */, // 0x6bfc0003 /* 0001aff0 - 0001aff3 [ 4] */, // 0x6bfd4006 /* 0001aff5 - 0001affb [ 7] */, // 0x6bff4001 /* 0001affd - 0001affe [ 2] */, // @@ -192,6 +194,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { 0x6c554000 /* 0001b155 - 0001b155 [ 1] */, // 0x6c590003 /* 0001b164 - 0001b167 [ 4] */, // 0x6c5c018b /* 0001b170 - 0001b2fb [ 396] */, // + 0x74c00056 /* 0001d300 - 0001d356 [ 87] */, // + 0x74d80016 /* 0001d360 - 0001d376 [ 23] */, // 0x7c010000 /* 0001f004 - 0001f004 [ 1] */, // 0x7c33c000 /* 0001f0cf - 0001f0cf [ 1] */, // 0x7c638000 /* 0001f18e - 0001f18e [ 1] */, // @@ -213,11 +217,10 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { 0x7dfc0000 /* 0001f7f0 - 0001f7f0 [ 1] */, // 0x7e4000ff /* 0001f900 - 0001f9ff [ 256] */, // 0x7e9c000c /* 0001fa70 - 0001fa7c [ 13] */, // - 0x7ea00008 /* 0001fa80 - 0001fa88 [ 9] */, // - 0x7ea4002d /* 0001fa90 - 0001fabd [ 46] */, // - 0x7eafc006 /* 0001fabf - 0001fac5 [ 7] */, // - 0x7eb3800d /* 0001face - 0001fadb [ 14] */, // - 0x7eb80008 /* 0001fae0 - 0001fae8 [ 9] */, // + 0x7ea00009 /* 0001fa80 - 0001fa89 [ 10] */, // + 0x7ea3c037 /* 0001fa8f - 0001fac6 [ 56] */, // + 0x7eb3800e /* 0001face - 0001fadc [ 15] */, // + 0x7eb7c00a /* 0001fadf - 0001fae9 [ 11] */, // 0x7ebc0008 /* 0001faf0 - 0001faf8 [ 9] */, // 0x80003fff /* 00020000 - 00023fff [16384] */, // 0x90003fff /* 00024000 - 00027fff [16384] */, // diff --git a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h index eb7500a828ccf0..9664622ab4e403 100644 --- a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h +++ b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h @@ -82,7 +82,7 @@ struct data { }; /// The data for UTF-8. -std::array, 1187> data_utf8 = {{ +std::array, 1093> data_utf8 = {{ {"\U00000020\U00000020", {32, 32}, {1, 2}}, {"\U00000020\U00000308\U00000020", {32, 32}, {3, 4}}, {"\U00000020\U0000000d", {32, 13}, {1, 2}}, @@ -91,8 +91,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000020\U00000308\U0000000a", {32, 10}, {3, 4}}, {"\U00000020\U00000001", {32, 1}, {1, 2}}, {"\U00000020\U00000308\U00000001", {32, 1}, {3, 4}}, - {"\U00000020\U0000034f", {32}, {3}}, - {"\U00000020\U00000308\U0000034f", {32}, {5}}, + {"\U00000020\U0000200c", {32}, {4}}, + {"\U00000020\U00000308\U0000200c", {32}, {6}}, {"\U00000020\U0001f1e6", {32, 127462}, {1, 5}}, {"\U00000020\U00000308\U0001f1e6", {32, 127462}, {3, 7}}, {"\U00000020\U00000600", {32, 1536}, {1, 3}}, @@ -109,8 +109,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000020\U00000308\U0000ac00", {32, 44032}, {3, 6}}, {"\U00000020\U0000ac01", {32, 44033}, {1, 4}}, {"\U00000020\U00000308\U0000ac01", {32, 44033}, {3, 6}}, - {"\U00000020\U00000900", {32}, {4}}, - {"\U00000020\U00000308\U00000900", {32}, {6}}, {"\U00000020\U00000903", {32}, {4}}, {"\U00000020\U00000308\U00000903", {32}, {6}}, {"\U00000020\U00000904", {32, 2308}, {1, 4}}, @@ -123,8 +121,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000020\U00000308\U0000231a", {32, 8986}, {3, 6}}, {"\U00000020\U00000300", {32}, {3}}, {"\U00000020\U00000308\U00000300", {32}, {5}}, - {"\U00000020\U0000093c", {32}, {4}}, - {"\U00000020\U00000308\U0000093c", {32}, {6}}, + {"\U00000020\U00000900", {32}, {4}}, + {"\U00000020\U00000308\U00000900", {32}, {6}}, {"\U00000020\U0000094d", {32}, {4}}, {"\U00000020\U00000308\U0000094d", {32}, {6}}, {"\U00000020\U0000200d", {32}, {4}}, @@ -139,8 +137,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000000d\U00000308\U0000000a", {13, 776, 10}, {1, 3, 4}}, {"\U0000000d\U00000001", {13, 1}, {1, 2}}, {"\U0000000d\U00000308\U00000001", {13, 776, 1}, {1, 3, 4}}, - {"\U0000000d\U0000034f", {13, 847}, {1, 3}}, - {"\U0000000d\U00000308\U0000034f", {13, 776}, {1, 5}}, + {"\U0000000d\U0000200c", {13, 8204}, {1, 4}}, + {"\U0000000d\U00000308\U0000200c", {13, 776}, {1, 6}}, {"\U0000000d\U0001f1e6", {13, 127462}, {1, 5}}, {"\U0000000d\U00000308\U0001f1e6", {13, 776, 127462}, {1, 3, 7}}, {"\U0000000d\U00000600", {13, 1536}, {1, 3}}, @@ -157,8 +155,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000000d\U00000308\U0000ac00", {13, 776, 44032}, {1, 3, 6}}, {"\U0000000d\U0000ac01", {13, 44033}, {1, 4}}, {"\U0000000d\U00000308\U0000ac01", {13, 776, 44033}, {1, 3, 6}}, - {"\U0000000d\U00000900", {13, 2304}, {1, 4}}, - {"\U0000000d\U00000308\U00000900", {13, 776}, {1, 6}}, {"\U0000000d\U00000903", {13, 2307}, {1, 4}}, {"\U0000000d\U00000308\U00000903", {13, 776}, {1, 6}}, {"\U0000000d\U00000904", {13, 2308}, {1, 4}}, @@ -171,8 +167,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000000d\U00000308\U0000231a", {13, 776, 8986}, {1, 3, 6}}, {"\U0000000d\U00000300", {13, 768}, {1, 3}}, {"\U0000000d\U00000308\U00000300", {13, 776}, {1, 5}}, - {"\U0000000d\U0000093c", {13, 2364}, {1, 4}}, - {"\U0000000d\U00000308\U0000093c", {13, 776}, {1, 6}}, + {"\U0000000d\U00000900", {13, 2304}, {1, 4}}, + {"\U0000000d\U00000308\U00000900", {13, 776}, {1, 6}}, {"\U0000000d\U0000094d", {13, 2381}, {1, 4}}, {"\U0000000d\U00000308\U0000094d", {13, 776}, {1, 6}}, {"\U0000000d\U0000200d", {13, 8205}, {1, 4}}, @@ -187,8 +183,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000000a\U00000308\U0000000a", {10, 776, 10}, {1, 3, 4}}, {"\U0000000a\U00000001", {10, 1}, {1, 2}}, {"\U0000000a\U00000308\U00000001", {10, 776, 1}, {1, 3, 4}}, - {"\U0000000a\U0000034f", {10, 847}, {1, 3}}, - {"\U0000000a\U00000308\U0000034f", {10, 776}, {1, 5}}, + {"\U0000000a\U0000200c", {10, 8204}, {1, 4}}, + {"\U0000000a\U00000308\U0000200c", {10, 776}, {1, 6}}, {"\U0000000a\U0001f1e6", {10, 127462}, {1, 5}}, {"\U0000000a\U00000308\U0001f1e6", {10, 776, 127462}, {1, 3, 7}}, {"\U0000000a\U00000600", {10, 1536}, {1, 3}}, @@ -205,8 +201,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000000a\U00000308\U0000ac00", {10, 776, 44032}, {1, 3, 6}}, {"\U0000000a\U0000ac01", {10, 44033}, {1, 4}}, {"\U0000000a\U00000308\U0000ac01", {10, 776, 44033}, {1, 3, 6}}, - {"\U0000000a\U00000900", {10, 2304}, {1, 4}}, - {"\U0000000a\U00000308\U00000900", {10, 776}, {1, 6}}, {"\U0000000a\U00000903", {10, 2307}, {1, 4}}, {"\U0000000a\U00000308\U00000903", {10, 776}, {1, 6}}, {"\U0000000a\U00000904", {10, 2308}, {1, 4}}, @@ -219,8 +213,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000000a\U00000308\U0000231a", {10, 776, 8986}, {1, 3, 6}}, {"\U0000000a\U00000300", {10, 768}, {1, 3}}, {"\U0000000a\U00000308\U00000300", {10, 776}, {1, 5}}, - {"\U0000000a\U0000093c", {10, 2364}, {1, 4}}, - {"\U0000000a\U00000308\U0000093c", {10, 776}, {1, 6}}, + {"\U0000000a\U00000900", {10, 2304}, {1, 4}}, + {"\U0000000a\U00000308\U00000900", {10, 776}, {1, 6}}, {"\U0000000a\U0000094d", {10, 2381}, {1, 4}}, {"\U0000000a\U00000308\U0000094d", {10, 776}, {1, 6}}, {"\U0000000a\U0000200d", {10, 8205}, {1, 4}}, @@ -235,8 +229,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000001\U00000308\U0000000a", {1, 776, 10}, {1, 3, 4}}, {"\U00000001\U00000001", {1, 1}, {1, 2}}, {"\U00000001\U00000308\U00000001", {1, 776, 1}, {1, 3, 4}}, - {"\U00000001\U0000034f", {1, 847}, {1, 3}}, - {"\U00000001\U00000308\U0000034f", {1, 776}, {1, 5}}, + {"\U00000001\U0000200c", {1, 8204}, {1, 4}}, + {"\U00000001\U00000308\U0000200c", {1, 776}, {1, 6}}, {"\U00000001\U0001f1e6", {1, 127462}, {1, 5}}, {"\U00000001\U00000308\U0001f1e6", {1, 776, 127462}, {1, 3, 7}}, {"\U00000001\U00000600", {1, 1536}, {1, 3}}, @@ -253,8 +247,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000001\U00000308\U0000ac00", {1, 776, 44032}, {1, 3, 6}}, {"\U00000001\U0000ac01", {1, 44033}, {1, 4}}, {"\U00000001\U00000308\U0000ac01", {1, 776, 44033}, {1, 3, 6}}, - {"\U00000001\U00000900", {1, 2304}, {1, 4}}, - {"\U00000001\U00000308\U00000900", {1, 776}, {1, 6}}, {"\U00000001\U00000903", {1, 2307}, {1, 4}}, {"\U00000001\U00000308\U00000903", {1, 776}, {1, 6}}, {"\U00000001\U00000904", {1, 2308}, {1, 4}}, @@ -267,62 +259,60 @@ std::array, 1187> data_utf8 = {{ {"\U00000001\U00000308\U0000231a", {1, 776, 8986}, {1, 3, 6}}, {"\U00000001\U00000300", {1, 768}, {1, 3}}, {"\U00000001\U00000308\U00000300", {1, 776}, {1, 5}}, - {"\U00000001\U0000093c", {1, 2364}, {1, 4}}, - {"\U00000001\U00000308\U0000093c", {1, 776}, {1, 6}}, + {"\U00000001\U00000900", {1, 2304}, {1, 4}}, + {"\U00000001\U00000308\U00000900", {1, 776}, {1, 6}}, {"\U00000001\U0000094d", {1, 2381}, {1, 4}}, {"\U00000001\U00000308\U0000094d", {1, 776}, {1, 6}}, {"\U00000001\U0000200d", {1, 8205}, {1, 4}}, {"\U00000001\U00000308\U0000200d", {1, 776}, {1, 6}}, {"\U00000001\U00000378", {1, 888}, {1, 3}}, {"\U00000001\U00000308\U00000378", {1, 776, 888}, {1, 3, 5}}, - {"\U0000034f\U00000020", {847, 32}, {2, 3}}, - {"\U0000034f\U00000308\U00000020", {847, 32}, {4, 5}}, - {"\U0000034f\U0000000d", {847, 13}, {2, 3}}, - {"\U0000034f\U00000308\U0000000d", {847, 13}, {4, 5}}, - {"\U0000034f\U0000000a", {847, 10}, {2, 3}}, - {"\U0000034f\U00000308\U0000000a", {847, 10}, {4, 5}}, - {"\U0000034f\U00000001", {847, 1}, {2, 3}}, - {"\U0000034f\U00000308\U00000001", {847, 1}, {4, 5}}, - {"\U0000034f\U0000034f", {847}, {4}}, - {"\U0000034f\U00000308\U0000034f", {847}, {6}}, - {"\U0000034f\U0001f1e6", {847, 127462}, {2, 6}}, - {"\U0000034f\U00000308\U0001f1e6", {847, 127462}, {4, 8}}, - {"\U0000034f\U00000600", {847, 1536}, {2, 4}}, - {"\U0000034f\U00000308\U00000600", {847, 1536}, {4, 6}}, - {"\U0000034f\U00000a03", {847}, {5}}, - {"\U0000034f\U00000308\U00000a03", {847}, {7}}, - {"\U0000034f\U00001100", {847, 4352}, {2, 5}}, - {"\U0000034f\U00000308\U00001100", {847, 4352}, {4, 7}}, - {"\U0000034f\U00001160", {847, 4448}, {2, 5}}, - {"\U0000034f\U00000308\U00001160", {847, 4448}, {4, 7}}, - {"\U0000034f\U000011a8", {847, 4520}, {2, 5}}, - {"\U0000034f\U00000308\U000011a8", {847, 4520}, {4, 7}}, - {"\U0000034f\U0000ac00", {847, 44032}, {2, 5}}, - {"\U0000034f\U00000308\U0000ac00", {847, 44032}, {4, 7}}, - {"\U0000034f\U0000ac01", {847, 44033}, {2, 5}}, - {"\U0000034f\U00000308\U0000ac01", {847, 44033}, {4, 7}}, - {"\U0000034f\U00000900", {847}, {5}}, - {"\U0000034f\U00000308\U00000900", {847}, {7}}, - {"\U0000034f\U00000903", {847}, {5}}, - {"\U0000034f\U00000308\U00000903", {847}, {7}}, - {"\U0000034f\U00000904", {847, 2308}, {2, 5}}, - {"\U0000034f\U00000308\U00000904", {847, 2308}, {4, 7}}, - {"\U0000034f\U00000d4e", {847, 3406}, {2, 5}}, - {"\U0000034f\U00000308\U00000d4e", {847, 3406}, {4, 7}}, - {"\U0000034f\U00000915", {847, 2325}, {2, 5}}, - {"\U0000034f\U00000308\U00000915", {847, 2325}, {4, 7}}, - {"\U0000034f\U0000231a", {847, 8986}, {2, 5}}, - {"\U0000034f\U00000308\U0000231a", {847, 8986}, {4, 7}}, - {"\U0000034f\U00000300", {847}, {4}}, - {"\U0000034f\U00000308\U00000300", {847}, {6}}, - {"\U0000034f\U0000093c", {847}, {5}}, - {"\U0000034f\U00000308\U0000093c", {847}, {7}}, - {"\U0000034f\U0000094d", {847}, {5}}, - {"\U0000034f\U00000308\U0000094d", {847}, {7}}, - {"\U0000034f\U0000200d", {847}, {5}}, - {"\U0000034f\U00000308\U0000200d", {847}, {7}}, - {"\U0000034f\U00000378", {847, 888}, {2, 4}}, - {"\U0000034f\U00000308\U00000378", {847, 888}, {4, 6}}, + {"\U0000200c\U00000020", {8204, 32}, {3, 4}}, + {"\U0000200c\U00000308\U00000020", {8204, 32}, {5, 6}}, + {"\U0000200c\U0000000d", {8204, 13}, {3, 4}}, + {"\U0000200c\U00000308\U0000000d", {8204, 13}, {5, 6}}, + {"\U0000200c\U0000000a", {8204, 10}, {3, 4}}, + {"\U0000200c\U00000308\U0000000a", {8204, 10}, {5, 6}}, + {"\U0000200c\U00000001", {8204, 1}, {3, 4}}, + {"\U0000200c\U00000308\U00000001", {8204, 1}, {5, 6}}, + {"\U0000200c\U0000200c", {8204}, {6}}, + {"\U0000200c\U00000308\U0000200c", {8204}, {8}}, + {"\U0000200c\U0001f1e6", {8204, 127462}, {3, 7}}, + {"\U0000200c\U00000308\U0001f1e6", {8204, 127462}, {5, 9}}, + {"\U0000200c\U00000600", {8204, 1536}, {3, 5}}, + {"\U0000200c\U00000308\U00000600", {8204, 1536}, {5, 7}}, + {"\U0000200c\U00000a03", {8204}, {6}}, + {"\U0000200c\U00000308\U00000a03", {8204}, {8}}, + {"\U0000200c\U00001100", {8204, 4352}, {3, 6}}, + {"\U0000200c\U00000308\U00001100", {8204, 4352}, {5, 8}}, + {"\U0000200c\U00001160", {8204, 4448}, {3, 6}}, + {"\U0000200c\U00000308\U00001160", {8204, 4448}, {5, 8}}, + {"\U0000200c\U000011a8", {8204, 4520}, {3, 6}}, + {"\U0000200c\U00000308\U000011a8", {8204, 4520}, {5, 8}}, + {"\U0000200c\U0000ac00", {8204, 44032}, {3, 6}}, + {"\U0000200c\U00000308\U0000ac00", {8204, 44032}, {5, 8}}, + {"\U0000200c\U0000ac01", {8204, 44033}, {3, 6}}, + {"\U0000200c\U00000308\U0000ac01", {8204, 44033}, {5, 8}}, + {"\U0000200c\U00000903", {8204}, {6}}, + {"\U0000200c\U00000308\U00000903", {8204}, {8}}, + {"\U0000200c\U00000904", {8204, 2308}, {3, 6}}, + {"\U0000200c\U00000308\U00000904", {8204, 2308}, {5, 8}}, + {"\U0000200c\U00000d4e", {8204, 3406}, {3, 6}}, + {"\U0000200c\U00000308\U00000d4e", {8204, 3406}, {5, 8}}, + {"\U0000200c\U00000915", {8204, 2325}, {3, 6}}, + {"\U0000200c\U00000308\U00000915", {8204, 2325}, {5, 8}}, + {"\U0000200c\U0000231a", {8204, 8986}, {3, 6}}, + {"\U0000200c\U00000308\U0000231a", {8204, 8986}, {5, 8}}, + {"\U0000200c\U00000300", {8204}, {5}}, + {"\U0000200c\U00000308\U00000300", {8204}, {7}}, + {"\U0000200c\U00000900", {8204}, {6}}, + {"\U0000200c\U00000308\U00000900", {8204}, {8}}, + {"\U0000200c\U0000094d", {8204}, {6}}, + {"\U0000200c\U00000308\U0000094d", {8204}, {8}}, + {"\U0000200c\U0000200d", {8204}, {6}}, + {"\U0000200c\U00000308\U0000200d", {8204}, {8}}, + {"\U0000200c\U00000378", {8204, 888}, {3, 5}}, + {"\U0000200c\U00000308\U00000378", {8204, 888}, {5, 7}}, {"\U0001f1e6\U00000020", {127462, 32}, {4, 5}}, {"\U0001f1e6\U00000308\U00000020", {127462, 32}, {6, 7}}, {"\U0001f1e6\U0000000d", {127462, 13}, {4, 5}}, @@ -331,8 +321,8 @@ std::array, 1187> data_utf8 = {{ {"\U0001f1e6\U00000308\U0000000a", {127462, 10}, {6, 7}}, {"\U0001f1e6\U00000001", {127462, 1}, {4, 5}}, {"\U0001f1e6\U00000308\U00000001", {127462, 1}, {6, 7}}, - {"\U0001f1e6\U0000034f", {127462}, {6}}, - {"\U0001f1e6\U00000308\U0000034f", {127462}, {8}}, + {"\U0001f1e6\U0000200c", {127462}, {7}}, + {"\U0001f1e6\U00000308\U0000200c", {127462}, {9}}, {"\U0001f1e6\U0001f1e6", {127462}, {8}}, {"\U0001f1e6\U00000308\U0001f1e6", {127462, 127462}, {6, 10}}, {"\U0001f1e6\U00000600", {127462, 1536}, {4, 6}}, @@ -349,8 +339,6 @@ std::array, 1187> data_utf8 = {{ {"\U0001f1e6\U00000308\U0000ac00", {127462, 44032}, {6, 9}}, {"\U0001f1e6\U0000ac01", {127462, 44033}, {4, 7}}, {"\U0001f1e6\U00000308\U0000ac01", {127462, 44033}, {6, 9}}, - {"\U0001f1e6\U00000900", {127462}, {7}}, - {"\U0001f1e6\U00000308\U00000900", {127462}, {9}}, {"\U0001f1e6\U00000903", {127462}, {7}}, {"\U0001f1e6\U00000308\U00000903", {127462}, {9}}, {"\U0001f1e6\U00000904", {127462, 2308}, {4, 7}}, @@ -363,8 +351,8 @@ std::array, 1187> data_utf8 = {{ {"\U0001f1e6\U00000308\U0000231a", {127462, 8986}, {6, 9}}, {"\U0001f1e6\U00000300", {127462}, {6}}, {"\U0001f1e6\U00000308\U00000300", {127462}, {8}}, - {"\U0001f1e6\U0000093c", {127462}, {7}}, - {"\U0001f1e6\U00000308\U0000093c", {127462}, {9}}, + {"\U0001f1e6\U00000900", {127462}, {7}}, + {"\U0001f1e6\U00000308\U00000900", {127462}, {9}}, {"\U0001f1e6\U0000094d", {127462}, {7}}, {"\U0001f1e6\U00000308\U0000094d", {127462}, {9}}, {"\U0001f1e6\U0000200d", {127462}, {7}}, @@ -379,8 +367,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000600\U00000308\U0000000a", {1536, 10}, {4, 5}}, {"\U00000600\U00000001", {1536, 1}, {2, 3}}, {"\U00000600\U00000308\U00000001", {1536, 1}, {4, 5}}, - {"\U00000600\U0000034f", {1536}, {4}}, - {"\U00000600\U00000308\U0000034f", {1536}, {6}}, + {"\U00000600\U0000200c", {1536}, {5}}, + {"\U00000600\U00000308\U0000200c", {1536}, {7}}, {"\U00000600\U0001f1e6", {1536}, {6}}, {"\U00000600\U00000308\U0001f1e6", {1536, 127462}, {4, 8}}, {"\U00000600\U00000600", {1536}, {4}}, @@ -397,8 +385,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000600\U00000308\U0000ac00", {1536, 44032}, {4, 7}}, {"\U00000600\U0000ac01", {1536}, {5}}, {"\U00000600\U00000308\U0000ac01", {1536, 44033}, {4, 7}}, - {"\U00000600\U00000900", {1536}, {5}}, - {"\U00000600\U00000308\U00000900", {1536}, {7}}, {"\U00000600\U00000903", {1536}, {5}}, {"\U00000600\U00000308\U00000903", {1536}, {7}}, {"\U00000600\U00000904", {1536}, {5}}, @@ -411,8 +397,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000600\U00000308\U0000231a", {1536, 8986}, {4, 7}}, {"\U00000600\U00000300", {1536}, {4}}, {"\U00000600\U00000308\U00000300", {1536}, {6}}, - {"\U00000600\U0000093c", {1536}, {5}}, - {"\U00000600\U00000308\U0000093c", {1536}, {7}}, + {"\U00000600\U00000900", {1536}, {5}}, + {"\U00000600\U00000308\U00000900", {1536}, {7}}, {"\U00000600\U0000094d", {1536}, {5}}, {"\U00000600\U00000308\U0000094d", {1536}, {7}}, {"\U00000600\U0000200d", {1536}, {5}}, @@ -427,8 +413,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000a03\U00000308\U0000000a", {2563, 10}, {5, 6}}, {"\U00000a03\U00000001", {2563, 1}, {3, 4}}, {"\U00000a03\U00000308\U00000001", {2563, 1}, {5, 6}}, - {"\U00000a03\U0000034f", {2563}, {5}}, - {"\U00000a03\U00000308\U0000034f", {2563}, {7}}, + {"\U00000a03\U0000200c", {2563}, {6}}, + {"\U00000a03\U00000308\U0000200c", {2563}, {8}}, {"\U00000a03\U0001f1e6", {2563, 127462}, {3, 7}}, {"\U00000a03\U00000308\U0001f1e6", {2563, 127462}, {5, 9}}, {"\U00000a03\U00000600", {2563, 1536}, {3, 5}}, @@ -445,8 +431,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000a03\U00000308\U0000ac00", {2563, 44032}, {5, 8}}, {"\U00000a03\U0000ac01", {2563, 44033}, {3, 6}}, {"\U00000a03\U00000308\U0000ac01", {2563, 44033}, {5, 8}}, - {"\U00000a03\U00000900", {2563}, {6}}, - {"\U00000a03\U00000308\U00000900", {2563}, {8}}, {"\U00000a03\U00000903", {2563}, {6}}, {"\U00000a03\U00000308\U00000903", {2563}, {8}}, {"\U00000a03\U00000904", {2563, 2308}, {3, 6}}, @@ -459,8 +443,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000a03\U00000308\U0000231a", {2563, 8986}, {5, 8}}, {"\U00000a03\U00000300", {2563}, {5}}, {"\U00000a03\U00000308\U00000300", {2563}, {7}}, - {"\U00000a03\U0000093c", {2563}, {6}}, - {"\U00000a03\U00000308\U0000093c", {2563}, {8}}, + {"\U00000a03\U00000900", {2563}, {6}}, + {"\U00000a03\U00000308\U00000900", {2563}, {8}}, {"\U00000a03\U0000094d", {2563}, {6}}, {"\U00000a03\U00000308\U0000094d", {2563}, {8}}, {"\U00000a03\U0000200d", {2563}, {6}}, @@ -475,8 +459,8 @@ std::array, 1187> data_utf8 = {{ {"\U00001100\U00000308\U0000000a", {4352, 10}, {5, 6}}, {"\U00001100\U00000001", {4352, 1}, {3, 4}}, {"\U00001100\U00000308\U00000001", {4352, 1}, {5, 6}}, - {"\U00001100\U0000034f", {4352}, {5}}, - {"\U00001100\U00000308\U0000034f", {4352}, {7}}, + {"\U00001100\U0000200c", {4352}, {6}}, + {"\U00001100\U00000308\U0000200c", {4352}, {8}}, {"\U00001100\U0001f1e6", {4352, 127462}, {3, 7}}, {"\U00001100\U00000308\U0001f1e6", {4352, 127462}, {5, 9}}, {"\U00001100\U00000600", {4352, 1536}, {3, 5}}, @@ -493,8 +477,6 @@ std::array, 1187> data_utf8 = {{ {"\U00001100\U00000308\U0000ac00", {4352, 44032}, {5, 8}}, {"\U00001100\U0000ac01", {4352}, {6}}, {"\U00001100\U00000308\U0000ac01", {4352, 44033}, {5, 8}}, - {"\U00001100\U00000900", {4352}, {6}}, - {"\U00001100\U00000308\U00000900", {4352}, {8}}, {"\U00001100\U00000903", {4352}, {6}}, {"\U00001100\U00000308\U00000903", {4352}, {8}}, {"\U00001100\U00000904", {4352, 2308}, {3, 6}}, @@ -507,8 +489,8 @@ std::array, 1187> data_utf8 = {{ {"\U00001100\U00000308\U0000231a", {4352, 8986}, {5, 8}}, {"\U00001100\U00000300", {4352}, {5}}, {"\U00001100\U00000308\U00000300", {4352}, {7}}, - {"\U00001100\U0000093c", {4352}, {6}}, - {"\U00001100\U00000308\U0000093c", {4352}, {8}}, + {"\U00001100\U00000900", {4352}, {6}}, + {"\U00001100\U00000308\U00000900", {4352}, {8}}, {"\U00001100\U0000094d", {4352}, {6}}, {"\U00001100\U00000308\U0000094d", {4352}, {8}}, {"\U00001100\U0000200d", {4352}, {6}}, @@ -523,8 +505,8 @@ std::array, 1187> data_utf8 = {{ {"\U00001160\U00000308\U0000000a", {4448, 10}, {5, 6}}, {"\U00001160\U00000001", {4448, 1}, {3, 4}}, {"\U00001160\U00000308\U00000001", {4448, 1}, {5, 6}}, - {"\U00001160\U0000034f", {4448}, {5}}, - {"\U00001160\U00000308\U0000034f", {4448}, {7}}, + {"\U00001160\U0000200c", {4448}, {6}}, + {"\U00001160\U00000308\U0000200c", {4448}, {8}}, {"\U00001160\U0001f1e6", {4448, 127462}, {3, 7}}, {"\U00001160\U00000308\U0001f1e6", {4448, 127462}, {5, 9}}, {"\U00001160\U00000600", {4448, 1536}, {3, 5}}, @@ -541,8 +523,6 @@ std::array, 1187> data_utf8 = {{ {"\U00001160\U00000308\U0000ac00", {4448, 44032}, {5, 8}}, {"\U00001160\U0000ac01", {4448, 44033}, {3, 6}}, {"\U00001160\U00000308\U0000ac01", {4448, 44033}, {5, 8}}, - {"\U00001160\U00000900", {4448}, {6}}, - {"\U00001160\U00000308\U00000900", {4448}, {8}}, {"\U00001160\U00000903", {4448}, {6}}, {"\U00001160\U00000308\U00000903", {4448}, {8}}, {"\U00001160\U00000904", {4448, 2308}, {3, 6}}, @@ -555,8 +535,8 @@ std::array, 1187> data_utf8 = {{ {"\U00001160\U00000308\U0000231a", {4448, 8986}, {5, 8}}, {"\U00001160\U00000300", {4448}, {5}}, {"\U00001160\U00000308\U00000300", {4448}, {7}}, - {"\U00001160\U0000093c", {4448}, {6}}, - {"\U00001160\U00000308\U0000093c", {4448}, {8}}, + {"\U00001160\U00000900", {4448}, {6}}, + {"\U00001160\U00000308\U00000900", {4448}, {8}}, {"\U00001160\U0000094d", {4448}, {6}}, {"\U00001160\U00000308\U0000094d", {4448}, {8}}, {"\U00001160\U0000200d", {4448}, {6}}, @@ -571,8 +551,8 @@ std::array, 1187> data_utf8 = {{ {"\U000011a8\U00000308\U0000000a", {4520, 10}, {5, 6}}, {"\U000011a8\U00000001", {4520, 1}, {3, 4}}, {"\U000011a8\U00000308\U00000001", {4520, 1}, {5, 6}}, - {"\U000011a8\U0000034f", {4520}, {5}}, - {"\U000011a8\U00000308\U0000034f", {4520}, {7}}, + {"\U000011a8\U0000200c", {4520}, {6}}, + {"\U000011a8\U00000308\U0000200c", {4520}, {8}}, {"\U000011a8\U0001f1e6", {4520, 127462}, {3, 7}}, {"\U000011a8\U00000308\U0001f1e6", {4520, 127462}, {5, 9}}, {"\U000011a8\U00000600", {4520, 1536}, {3, 5}}, @@ -589,8 +569,6 @@ std::array, 1187> data_utf8 = {{ {"\U000011a8\U00000308\U0000ac00", {4520, 44032}, {5, 8}}, {"\U000011a8\U0000ac01", {4520, 44033}, {3, 6}}, {"\U000011a8\U00000308\U0000ac01", {4520, 44033}, {5, 8}}, - {"\U000011a8\U00000900", {4520}, {6}}, - {"\U000011a8\U00000308\U00000900", {4520}, {8}}, {"\U000011a8\U00000903", {4520}, {6}}, {"\U000011a8\U00000308\U00000903", {4520}, {8}}, {"\U000011a8\U00000904", {4520, 2308}, {3, 6}}, @@ -603,8 +581,8 @@ std::array, 1187> data_utf8 = {{ {"\U000011a8\U00000308\U0000231a", {4520, 8986}, {5, 8}}, {"\U000011a8\U00000300", {4520}, {5}}, {"\U000011a8\U00000308\U00000300", {4520}, {7}}, - {"\U000011a8\U0000093c", {4520}, {6}}, - {"\U000011a8\U00000308\U0000093c", {4520}, {8}}, + {"\U000011a8\U00000900", {4520}, {6}}, + {"\U000011a8\U00000308\U00000900", {4520}, {8}}, {"\U000011a8\U0000094d", {4520}, {6}}, {"\U000011a8\U00000308\U0000094d", {4520}, {8}}, {"\U000011a8\U0000200d", {4520}, {6}}, @@ -619,8 +597,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac00\U00000308\U0000000a", {44032, 10}, {5, 6}}, {"\U0000ac00\U00000001", {44032, 1}, {3, 4}}, {"\U0000ac00\U00000308\U00000001", {44032, 1}, {5, 6}}, - {"\U0000ac00\U0000034f", {44032}, {5}}, - {"\U0000ac00\U00000308\U0000034f", {44032}, {7}}, + {"\U0000ac00\U0000200c", {44032}, {6}}, + {"\U0000ac00\U00000308\U0000200c", {44032}, {8}}, {"\U0000ac00\U0001f1e6", {44032, 127462}, {3, 7}}, {"\U0000ac00\U00000308\U0001f1e6", {44032, 127462}, {5, 9}}, {"\U0000ac00\U00000600", {44032, 1536}, {3, 5}}, @@ -637,8 +615,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac00\U00000308\U0000ac00", {44032, 44032}, {5, 8}}, {"\U0000ac00\U0000ac01", {44032, 44033}, {3, 6}}, {"\U0000ac00\U00000308\U0000ac01", {44032, 44033}, {5, 8}}, - {"\U0000ac00\U00000900", {44032}, {6}}, - {"\U0000ac00\U00000308\U00000900", {44032}, {8}}, {"\U0000ac00\U00000903", {44032}, {6}}, {"\U0000ac00\U00000308\U00000903", {44032}, {8}}, {"\U0000ac00\U00000904", {44032, 2308}, {3, 6}}, @@ -651,8 +627,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac00\U00000308\U0000231a", {44032, 8986}, {5, 8}}, {"\U0000ac00\U00000300", {44032}, {5}}, {"\U0000ac00\U00000308\U00000300", {44032}, {7}}, - {"\U0000ac00\U0000093c", {44032}, {6}}, - {"\U0000ac00\U00000308\U0000093c", {44032}, {8}}, + {"\U0000ac00\U00000900", {44032}, {6}}, + {"\U0000ac00\U00000308\U00000900", {44032}, {8}}, {"\U0000ac00\U0000094d", {44032}, {6}}, {"\U0000ac00\U00000308\U0000094d", {44032}, {8}}, {"\U0000ac00\U0000200d", {44032}, {6}}, @@ -667,8 +643,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac01\U00000308\U0000000a", {44033, 10}, {5, 6}}, {"\U0000ac01\U00000001", {44033, 1}, {3, 4}}, {"\U0000ac01\U00000308\U00000001", {44033, 1}, {5, 6}}, - {"\U0000ac01\U0000034f", {44033}, {5}}, - {"\U0000ac01\U00000308\U0000034f", {44033}, {7}}, + {"\U0000ac01\U0000200c", {44033}, {6}}, + {"\U0000ac01\U00000308\U0000200c", {44033}, {8}}, {"\U0000ac01\U0001f1e6", {44033, 127462}, {3, 7}}, {"\U0000ac01\U00000308\U0001f1e6", {44033, 127462}, {5, 9}}, {"\U0000ac01\U00000600", {44033, 1536}, {3, 5}}, @@ -685,8 +661,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac01\U00000308\U0000ac00", {44033, 44032}, {5, 8}}, {"\U0000ac01\U0000ac01", {44033, 44033}, {3, 6}}, {"\U0000ac01\U00000308\U0000ac01", {44033, 44033}, {5, 8}}, - {"\U0000ac01\U00000900", {44033}, {6}}, - {"\U0000ac01\U00000308\U00000900", {44033}, {8}}, {"\U0000ac01\U00000903", {44033}, {6}}, {"\U0000ac01\U00000308\U00000903", {44033}, {8}}, {"\U0000ac01\U00000904", {44033, 2308}, {3, 6}}, @@ -699,62 +673,14 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac01\U00000308\U0000231a", {44033, 8986}, {5, 8}}, {"\U0000ac01\U00000300", {44033}, {5}}, {"\U0000ac01\U00000308\U00000300", {44033}, {7}}, - {"\U0000ac01\U0000093c", {44033}, {6}}, - {"\U0000ac01\U00000308\U0000093c", {44033}, {8}}, + {"\U0000ac01\U00000900", {44033}, {6}}, + {"\U0000ac01\U00000308\U00000900", {44033}, {8}}, {"\U0000ac01\U0000094d", {44033}, {6}}, {"\U0000ac01\U00000308\U0000094d", {44033}, {8}}, {"\U0000ac01\U0000200d", {44033}, {6}}, {"\U0000ac01\U00000308\U0000200d", {44033}, {8}}, {"\U0000ac01\U00000378", {44033, 888}, {3, 5}}, {"\U0000ac01\U00000308\U00000378", {44033, 888}, {5, 7}}, - {"\U00000900\U00000020", {2304, 32}, {3, 4}}, - {"\U00000900\U00000308\U00000020", {2304, 32}, {5, 6}}, - {"\U00000900\U0000000d", {2304, 13}, {3, 4}}, - {"\U00000900\U00000308\U0000000d", {2304, 13}, {5, 6}}, - {"\U00000900\U0000000a", {2304, 10}, {3, 4}}, - {"\U00000900\U00000308\U0000000a", {2304, 10}, {5, 6}}, - {"\U00000900\U00000001", {2304, 1}, {3, 4}}, - {"\U00000900\U00000308\U00000001", {2304, 1}, {5, 6}}, - {"\U00000900\U0000034f", {2304}, {5}}, - {"\U00000900\U00000308\U0000034f", {2304}, {7}}, - {"\U00000900\U0001f1e6", {2304, 127462}, {3, 7}}, - {"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {5, 9}}, - {"\U00000900\U00000600", {2304, 1536}, {3, 5}}, - {"\U00000900\U00000308\U00000600", {2304, 1536}, {5, 7}}, - {"\U00000900\U00000a03", {2304}, {6}}, - {"\U00000900\U00000308\U00000a03", {2304}, {8}}, - {"\U00000900\U00001100", {2304, 4352}, {3, 6}}, - {"\U00000900\U00000308\U00001100", {2304, 4352}, {5, 8}}, - {"\U00000900\U00001160", {2304, 4448}, {3, 6}}, - {"\U00000900\U00000308\U00001160", {2304, 4448}, {5, 8}}, - {"\U00000900\U000011a8", {2304, 4520}, {3, 6}}, - {"\U00000900\U00000308\U000011a8", {2304, 4520}, {5, 8}}, - {"\U00000900\U0000ac00", {2304, 44032}, {3, 6}}, - {"\U00000900\U00000308\U0000ac00", {2304, 44032}, {5, 8}}, - {"\U00000900\U0000ac01", {2304, 44033}, {3, 6}}, - {"\U00000900\U00000308\U0000ac01", {2304, 44033}, {5, 8}}, - {"\U00000900\U00000900", {2304}, {6}}, - {"\U00000900\U00000308\U00000900", {2304}, {8}}, - {"\U00000900\U00000903", {2304}, {6}}, - {"\U00000900\U00000308\U00000903", {2304}, {8}}, - {"\U00000900\U00000904", {2304, 2308}, {3, 6}}, - {"\U00000900\U00000308\U00000904", {2304, 2308}, {5, 8}}, - {"\U00000900\U00000d4e", {2304, 3406}, {3, 6}}, - {"\U00000900\U00000308\U00000d4e", {2304, 3406}, {5, 8}}, - {"\U00000900\U00000915", {2304, 2325}, {3, 6}}, - {"\U00000900\U00000308\U00000915", {2304, 2325}, {5, 8}}, - {"\U00000900\U0000231a", {2304, 8986}, {3, 6}}, - {"\U00000900\U00000308\U0000231a", {2304, 8986}, {5, 8}}, - {"\U00000900\U00000300", {2304}, {5}}, - {"\U00000900\U00000308\U00000300", {2304}, {7}}, - {"\U00000900\U0000093c", {2304}, {6}}, - {"\U00000900\U00000308\U0000093c", {2304}, {8}}, - {"\U00000900\U0000094d", {2304}, {6}}, - {"\U00000900\U00000308\U0000094d", {2304}, {8}}, - {"\U00000900\U0000200d", {2304}, {6}}, - {"\U00000900\U00000308\U0000200d", {2304}, {8}}, - {"\U00000900\U00000378", {2304, 888}, {3, 5}}, - {"\U00000900\U00000308\U00000378", {2304, 888}, {5, 7}}, {"\U00000903\U00000020", {2307, 32}, {3, 4}}, {"\U00000903\U00000308\U00000020", {2307, 32}, {5, 6}}, {"\U00000903\U0000000d", {2307, 13}, {3, 4}}, @@ -763,8 +689,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000903\U00000308\U0000000a", {2307, 10}, {5, 6}}, {"\U00000903\U00000001", {2307, 1}, {3, 4}}, {"\U00000903\U00000308\U00000001", {2307, 1}, {5, 6}}, - {"\U00000903\U0000034f", {2307}, {5}}, - {"\U00000903\U00000308\U0000034f", {2307}, {7}}, + {"\U00000903\U0000200c", {2307}, {6}}, + {"\U00000903\U00000308\U0000200c", {2307}, {8}}, {"\U00000903\U0001f1e6", {2307, 127462}, {3, 7}}, {"\U00000903\U00000308\U0001f1e6", {2307, 127462}, {5, 9}}, {"\U00000903\U00000600", {2307, 1536}, {3, 5}}, @@ -781,8 +707,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000903\U00000308\U0000ac00", {2307, 44032}, {5, 8}}, {"\U00000903\U0000ac01", {2307, 44033}, {3, 6}}, {"\U00000903\U00000308\U0000ac01", {2307, 44033}, {5, 8}}, - {"\U00000903\U00000900", {2307}, {6}}, - {"\U00000903\U00000308\U00000900", {2307}, {8}}, {"\U00000903\U00000903", {2307}, {6}}, {"\U00000903\U00000308\U00000903", {2307}, {8}}, {"\U00000903\U00000904", {2307, 2308}, {3, 6}}, @@ -795,8 +719,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000903\U00000308\U0000231a", {2307, 8986}, {5, 8}}, {"\U00000903\U00000300", {2307}, {5}}, {"\U00000903\U00000308\U00000300", {2307}, {7}}, - {"\U00000903\U0000093c", {2307}, {6}}, - {"\U00000903\U00000308\U0000093c", {2307}, {8}}, + {"\U00000903\U00000900", {2307}, {6}}, + {"\U00000903\U00000308\U00000900", {2307}, {8}}, {"\U00000903\U0000094d", {2307}, {6}}, {"\U00000903\U00000308\U0000094d", {2307}, {8}}, {"\U00000903\U0000200d", {2307}, {6}}, @@ -811,8 +735,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000904\U00000308\U0000000a", {2308, 10}, {5, 6}}, {"\U00000904\U00000001", {2308, 1}, {3, 4}}, {"\U00000904\U00000308\U00000001", {2308, 1}, {5, 6}}, - {"\U00000904\U0000034f", {2308}, {5}}, - {"\U00000904\U00000308\U0000034f", {2308}, {7}}, + {"\U00000904\U0000200c", {2308}, {6}}, + {"\U00000904\U00000308\U0000200c", {2308}, {8}}, {"\U00000904\U0001f1e6", {2308, 127462}, {3, 7}}, {"\U00000904\U00000308\U0001f1e6", {2308, 127462}, {5, 9}}, {"\U00000904\U00000600", {2308, 1536}, {3, 5}}, @@ -829,8 +753,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000904\U00000308\U0000ac00", {2308, 44032}, {5, 8}}, {"\U00000904\U0000ac01", {2308, 44033}, {3, 6}}, {"\U00000904\U00000308\U0000ac01", {2308, 44033}, {5, 8}}, - {"\U00000904\U00000900", {2308}, {6}}, - {"\U00000904\U00000308\U00000900", {2308}, {8}}, {"\U00000904\U00000903", {2308}, {6}}, {"\U00000904\U00000308\U00000903", {2308}, {8}}, {"\U00000904\U00000904", {2308, 2308}, {3, 6}}, @@ -843,8 +765,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000904\U00000308\U0000231a", {2308, 8986}, {5, 8}}, {"\U00000904\U00000300", {2308}, {5}}, {"\U00000904\U00000308\U00000300", {2308}, {7}}, - {"\U00000904\U0000093c", {2308}, {6}}, - {"\U00000904\U00000308\U0000093c", {2308}, {8}}, + {"\U00000904\U00000900", {2308}, {6}}, + {"\U00000904\U00000308\U00000900", {2308}, {8}}, {"\U00000904\U0000094d", {2308}, {6}}, {"\U00000904\U00000308\U0000094d", {2308}, {8}}, {"\U00000904\U0000200d", {2308}, {6}}, @@ -859,8 +781,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000d4e\U00000308\U0000000a", {3406, 10}, {5, 6}}, {"\U00000d4e\U00000001", {3406, 1}, {3, 4}}, {"\U00000d4e\U00000308\U00000001", {3406, 1}, {5, 6}}, - {"\U00000d4e\U0000034f", {3406}, {5}}, - {"\U00000d4e\U00000308\U0000034f", {3406}, {7}}, + {"\U00000d4e\U0000200c", {3406}, {6}}, + {"\U00000d4e\U00000308\U0000200c", {3406}, {8}}, {"\U00000d4e\U0001f1e6", {3406}, {7}}, {"\U00000d4e\U00000308\U0001f1e6", {3406, 127462}, {5, 9}}, {"\U00000d4e\U00000600", {3406}, {5}}, @@ -877,8 +799,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000d4e\U00000308\U0000ac00", {3406, 44032}, {5, 8}}, {"\U00000d4e\U0000ac01", {3406}, {6}}, {"\U00000d4e\U00000308\U0000ac01", {3406, 44033}, {5, 8}}, - {"\U00000d4e\U00000900", {3406}, {6}}, - {"\U00000d4e\U00000308\U00000900", {3406}, {8}}, {"\U00000d4e\U00000903", {3406}, {6}}, {"\U00000d4e\U00000308\U00000903", {3406}, {8}}, {"\U00000d4e\U00000904", {3406}, {6}}, @@ -891,8 +811,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000d4e\U00000308\U0000231a", {3406, 8986}, {5, 8}}, {"\U00000d4e\U00000300", {3406}, {5}}, {"\U00000d4e\U00000308\U00000300", {3406}, {7}}, - {"\U00000d4e\U0000093c", {3406}, {6}}, - {"\U00000d4e\U00000308\U0000093c", {3406}, {8}}, + {"\U00000d4e\U00000900", {3406}, {6}}, + {"\U00000d4e\U00000308\U00000900", {3406}, {8}}, {"\U00000d4e\U0000094d", {3406}, {6}}, {"\U00000d4e\U00000308\U0000094d", {3406}, {8}}, {"\U00000d4e\U0000200d", {3406}, {6}}, @@ -907,8 +827,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000915\U00000308\U0000000a", {2325, 10}, {5, 6}}, {"\U00000915\U00000001", {2325, 1}, {3, 4}}, {"\U00000915\U00000308\U00000001", {2325, 1}, {5, 6}}, - {"\U00000915\U0000034f", {2325}, {5}}, - {"\U00000915\U00000308\U0000034f", {2325}, {7}}, + {"\U00000915\U0000200c", {2325}, {6}}, + {"\U00000915\U00000308\U0000200c", {2325}, {8}}, {"\U00000915\U0001f1e6", {2325, 127462}, {3, 7}}, {"\U00000915\U00000308\U0001f1e6", {2325, 127462}, {5, 9}}, {"\U00000915\U00000600", {2325, 1536}, {3, 5}}, @@ -925,8 +845,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000915\U00000308\U0000ac00", {2325, 44032}, {5, 8}}, {"\U00000915\U0000ac01", {2325, 44033}, {3, 6}}, {"\U00000915\U00000308\U0000ac01", {2325, 44033}, {5, 8}}, - {"\U00000915\U00000900", {2325}, {6}}, - {"\U00000915\U00000308\U00000900", {2325}, {8}}, {"\U00000915\U00000903", {2325}, {6}}, {"\U00000915\U00000308\U00000903", {2325}, {8}}, {"\U00000915\U00000904", {2325, 2308}, {3, 6}}, @@ -939,8 +857,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000915\U00000308\U0000231a", {2325, 8986}, {5, 8}}, {"\U00000915\U00000300", {2325}, {5}}, {"\U00000915\U00000308\U00000300", {2325}, {7}}, - {"\U00000915\U0000093c", {2325}, {6}}, - {"\U00000915\U00000308\U0000093c", {2325}, {8}}, + {"\U00000915\U00000900", {2325}, {6}}, + {"\U00000915\U00000308\U00000900", {2325}, {8}}, {"\U00000915\U0000094d", {2325}, {6}}, {"\U00000915\U00000308\U0000094d", {2325}, {8}}, {"\U00000915\U0000200d", {2325}, {6}}, @@ -955,8 +873,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000231a\U00000308\U0000000a", {8986, 10}, {5, 6}}, {"\U0000231a\U00000001", {8986, 1}, {3, 4}}, {"\U0000231a\U00000308\U00000001", {8986, 1}, {5, 6}}, - {"\U0000231a\U0000034f", {8986}, {5}}, - {"\U0000231a\U00000308\U0000034f", {8986}, {7}}, + {"\U0000231a\U0000200c", {8986}, {6}}, + {"\U0000231a\U00000308\U0000200c", {8986}, {8}}, {"\U0000231a\U0001f1e6", {8986, 127462}, {3, 7}}, {"\U0000231a\U00000308\U0001f1e6", {8986, 127462}, {5, 9}}, {"\U0000231a\U00000600", {8986, 1536}, {3, 5}}, @@ -973,8 +891,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000231a\U00000308\U0000ac00", {8986, 44032}, {5, 8}}, {"\U0000231a\U0000ac01", {8986, 44033}, {3, 6}}, {"\U0000231a\U00000308\U0000ac01", {8986, 44033}, {5, 8}}, - {"\U0000231a\U00000900", {8986}, {6}}, - {"\U0000231a\U00000308\U00000900", {8986}, {8}}, {"\U0000231a\U00000903", {8986}, {6}}, {"\U0000231a\U00000308\U00000903", {8986}, {8}}, {"\U0000231a\U00000904", {8986, 2308}, {3, 6}}, @@ -987,8 +903,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000231a\U00000308\U0000231a", {8986, 8986}, {5, 8}}, {"\U0000231a\U00000300", {8986}, {5}}, {"\U0000231a\U00000308\U00000300", {8986}, {7}}, - {"\U0000231a\U0000093c", {8986}, {6}}, - {"\U0000231a\U00000308\U0000093c", {8986}, {8}}, + {"\U0000231a\U00000900", {8986}, {6}}, + {"\U0000231a\U00000308\U00000900", {8986}, {8}}, {"\U0000231a\U0000094d", {8986}, {6}}, {"\U0000231a\U00000308\U0000094d", {8986}, {8}}, {"\U0000231a\U0000200d", {8986}, {6}}, @@ -1003,8 +919,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000300\U00000308\U0000000a", {768, 10}, {4, 5}}, {"\U00000300\U00000001", {768, 1}, {2, 3}}, {"\U00000300\U00000308\U00000001", {768, 1}, {4, 5}}, - {"\U00000300\U0000034f", {768}, {4}}, - {"\U00000300\U00000308\U0000034f", {768}, {6}}, + {"\U00000300\U0000200c", {768}, {5}}, + {"\U00000300\U00000308\U0000200c", {768}, {7}}, {"\U00000300\U0001f1e6", {768, 127462}, {2, 6}}, {"\U00000300\U00000308\U0001f1e6", {768, 127462}, {4, 8}}, {"\U00000300\U00000600", {768, 1536}, {2, 4}}, @@ -1021,8 +937,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000300\U00000308\U0000ac00", {768, 44032}, {4, 7}}, {"\U00000300\U0000ac01", {768, 44033}, {2, 5}}, {"\U00000300\U00000308\U0000ac01", {768, 44033}, {4, 7}}, - {"\U00000300\U00000900", {768}, {5}}, - {"\U00000300\U00000308\U00000900", {768}, {7}}, {"\U00000300\U00000903", {768}, {5}}, {"\U00000300\U00000308\U00000903", {768}, {7}}, {"\U00000300\U00000904", {768, 2308}, {2, 5}}, @@ -1035,62 +949,60 @@ std::array, 1187> data_utf8 = {{ {"\U00000300\U00000308\U0000231a", {768, 8986}, {4, 7}}, {"\U00000300\U00000300", {768}, {4}}, {"\U00000300\U00000308\U00000300", {768}, {6}}, - {"\U00000300\U0000093c", {768}, {5}}, - {"\U00000300\U00000308\U0000093c", {768}, {7}}, + {"\U00000300\U00000900", {768}, {5}}, + {"\U00000300\U00000308\U00000900", {768}, {7}}, {"\U00000300\U0000094d", {768}, {5}}, {"\U00000300\U00000308\U0000094d", {768}, {7}}, {"\U00000300\U0000200d", {768}, {5}}, {"\U00000300\U00000308\U0000200d", {768}, {7}}, {"\U00000300\U00000378", {768, 888}, {2, 4}}, {"\U00000300\U00000308\U00000378", {768, 888}, {4, 6}}, - {"\U0000093c\U00000020", {2364, 32}, {3, 4}}, - {"\U0000093c\U00000308\U00000020", {2364, 32}, {5, 6}}, - {"\U0000093c\U0000000d", {2364, 13}, {3, 4}}, - {"\U0000093c\U00000308\U0000000d", {2364, 13}, {5, 6}}, - {"\U0000093c\U0000000a", {2364, 10}, {3, 4}}, - {"\U0000093c\U00000308\U0000000a", {2364, 10}, {5, 6}}, - {"\U0000093c\U00000001", {2364, 1}, {3, 4}}, - {"\U0000093c\U00000308\U00000001", {2364, 1}, {5, 6}}, - {"\U0000093c\U0000034f", {2364}, {5}}, - {"\U0000093c\U00000308\U0000034f", {2364}, {7}}, - {"\U0000093c\U0001f1e6", {2364, 127462}, {3, 7}}, - {"\U0000093c\U00000308\U0001f1e6", {2364, 127462}, {5, 9}}, - {"\U0000093c\U00000600", {2364, 1536}, {3, 5}}, - {"\U0000093c\U00000308\U00000600", {2364, 1536}, {5, 7}}, - {"\U0000093c\U00000a03", {2364}, {6}}, - {"\U0000093c\U00000308\U00000a03", {2364}, {8}}, - {"\U0000093c\U00001100", {2364, 4352}, {3, 6}}, - {"\U0000093c\U00000308\U00001100", {2364, 4352}, {5, 8}}, - {"\U0000093c\U00001160", {2364, 4448}, {3, 6}}, - {"\U0000093c\U00000308\U00001160", {2364, 4448}, {5, 8}}, - {"\U0000093c\U000011a8", {2364, 4520}, {3, 6}}, - {"\U0000093c\U00000308\U000011a8", {2364, 4520}, {5, 8}}, - {"\U0000093c\U0000ac00", {2364, 44032}, {3, 6}}, - {"\U0000093c\U00000308\U0000ac00", {2364, 44032}, {5, 8}}, - {"\U0000093c\U0000ac01", {2364, 44033}, {3, 6}}, - {"\U0000093c\U00000308\U0000ac01", {2364, 44033}, {5, 8}}, - {"\U0000093c\U00000900", {2364}, {6}}, - {"\U0000093c\U00000308\U00000900", {2364}, {8}}, - {"\U0000093c\U00000903", {2364}, {6}}, - {"\U0000093c\U00000308\U00000903", {2364}, {8}}, - {"\U0000093c\U00000904", {2364, 2308}, {3, 6}}, - {"\U0000093c\U00000308\U00000904", {2364, 2308}, {5, 8}}, - {"\U0000093c\U00000d4e", {2364, 3406}, {3, 6}}, - {"\U0000093c\U00000308\U00000d4e", {2364, 3406}, {5, 8}}, - {"\U0000093c\U00000915", {2364, 2325}, {3, 6}}, - {"\U0000093c\U00000308\U00000915", {2364, 2325}, {5, 8}}, - {"\U0000093c\U0000231a", {2364, 8986}, {3, 6}}, - {"\U0000093c\U00000308\U0000231a", {2364, 8986}, {5, 8}}, - {"\U0000093c\U00000300", {2364}, {5}}, - {"\U0000093c\U00000308\U00000300", {2364}, {7}}, - {"\U0000093c\U0000093c", {2364}, {6}}, - {"\U0000093c\U00000308\U0000093c", {2364}, {8}}, - {"\U0000093c\U0000094d", {2364}, {6}}, - {"\U0000093c\U00000308\U0000094d", {2364}, {8}}, - {"\U0000093c\U0000200d", {2364}, {6}}, - {"\U0000093c\U00000308\U0000200d", {2364}, {8}}, - {"\U0000093c\U00000378", {2364, 888}, {3, 5}}, - {"\U0000093c\U00000308\U00000378", {2364, 888}, {5, 7}}, + {"\U00000900\U00000020", {2304, 32}, {3, 4}}, + {"\U00000900\U00000308\U00000020", {2304, 32}, {5, 6}}, + {"\U00000900\U0000000d", {2304, 13}, {3, 4}}, + {"\U00000900\U00000308\U0000000d", {2304, 13}, {5, 6}}, + {"\U00000900\U0000000a", {2304, 10}, {3, 4}}, + {"\U00000900\U00000308\U0000000a", {2304, 10}, {5, 6}}, + {"\U00000900\U00000001", {2304, 1}, {3, 4}}, + {"\U00000900\U00000308\U00000001", {2304, 1}, {5, 6}}, + {"\U00000900\U0000200c", {2304}, {6}}, + {"\U00000900\U00000308\U0000200c", {2304}, {8}}, + {"\U00000900\U0001f1e6", {2304, 127462}, {3, 7}}, + {"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {5, 9}}, + {"\U00000900\U00000600", {2304, 1536}, {3, 5}}, + {"\U00000900\U00000308\U00000600", {2304, 1536}, {5, 7}}, + {"\U00000900\U00000a03", {2304}, {6}}, + {"\U00000900\U00000308\U00000a03", {2304}, {8}}, + {"\U00000900\U00001100", {2304, 4352}, {3, 6}}, + {"\U00000900\U00000308\U00001100", {2304, 4352}, {5, 8}}, + {"\U00000900\U00001160", {2304, 4448}, {3, 6}}, + {"\U00000900\U00000308\U00001160", {2304, 4448}, {5, 8}}, + {"\U00000900\U000011a8", {2304, 4520}, {3, 6}}, + {"\U00000900\U00000308\U000011a8", {2304, 4520}, {5, 8}}, + {"\U00000900\U0000ac00", {2304, 44032}, {3, 6}}, + {"\U00000900\U00000308\U0000ac00", {2304, 44032}, {5, 8}}, + {"\U00000900\U0000ac01", {2304, 44033}, {3, 6}}, + {"\U00000900\U00000308\U0000ac01", {2304, 44033}, {5, 8}}, + {"\U00000900\U00000903", {2304}, {6}}, + {"\U00000900\U00000308\U00000903", {2304}, {8}}, + {"\U00000900\U00000904", {2304, 2308}, {3, 6}}, + {"\U00000900\U00000308\U00000904", {2304, 2308}, {5, 8}}, + {"\U00000900\U00000d4e", {2304, 3406}, {3, 6}}, + {"\U00000900\U00000308\U00000d4e", {2304, 3406}, {5, 8}}, + {"\U00000900\U00000915", {2304, 2325}, {3, 6}}, + {"\U00000900\U00000308\U00000915", {2304, 2325}, {5, 8}}, + {"\U00000900\U0000231a", {2304, 8986}, {3, 6}}, + {"\U00000900\U00000308\U0000231a", {2304, 8986}, {5, 8}}, + {"\U00000900\U00000300", {2304}, {5}}, + {"\U00000900\U00000308\U00000300", {2304}, {7}}, + {"\U00000900\U00000900", {2304}, {6}}, + {"\U00000900\U00000308\U00000900", {2304}, {8}}, + {"\U00000900\U0000094d", {2304}, {6}}, + {"\U00000900\U00000308\U0000094d", {2304}, {8}}, + {"\U00000900\U0000200d", {2304}, {6}}, + {"\U00000900\U00000308\U0000200d", {2304}, {8}}, + {"\U00000900\U00000378", {2304, 888}, {3, 5}}, + {"\U00000900\U00000308\U00000378", {2304, 888}, {5, 7}}, {"\U0000094d\U00000020", {2381, 32}, {3, 4}}, {"\U0000094d\U00000308\U00000020", {2381, 32}, {5, 6}}, {"\U0000094d\U0000000d", {2381, 13}, {3, 4}}, @@ -1099,8 +1011,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000094d\U00000308\U0000000a", {2381, 10}, {5, 6}}, {"\U0000094d\U00000001", {2381, 1}, {3, 4}}, {"\U0000094d\U00000308\U00000001", {2381, 1}, {5, 6}}, - {"\U0000094d\U0000034f", {2381}, {5}}, - {"\U0000094d\U00000308\U0000034f", {2381}, {7}}, + {"\U0000094d\U0000200c", {2381}, {6}}, + {"\U0000094d\U00000308\U0000200c", {2381}, {8}}, {"\U0000094d\U0001f1e6", {2381, 127462}, {3, 7}}, {"\U0000094d\U00000308\U0001f1e6", {2381, 127462}, {5, 9}}, {"\U0000094d\U00000600", {2381, 1536}, {3, 5}}, @@ -1117,8 +1029,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000094d\U00000308\U0000ac00", {2381, 44032}, {5, 8}}, {"\U0000094d\U0000ac01", {2381, 44033}, {3, 6}}, {"\U0000094d\U00000308\U0000ac01", {2381, 44033}, {5, 8}}, - {"\U0000094d\U00000900", {2381}, {6}}, - {"\U0000094d\U00000308\U00000900", {2381}, {8}}, {"\U0000094d\U00000903", {2381}, {6}}, {"\U0000094d\U00000308\U00000903", {2381}, {8}}, {"\U0000094d\U00000904", {2381, 2308}, {3, 6}}, @@ -1131,8 +1041,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000094d\U00000308\U0000231a", {2381, 8986}, {5, 8}}, {"\U0000094d\U00000300", {2381}, {5}}, {"\U0000094d\U00000308\U00000300", {2381}, {7}}, - {"\U0000094d\U0000093c", {2381}, {6}}, - {"\U0000094d\U00000308\U0000093c", {2381}, {8}}, + {"\U0000094d\U00000900", {2381}, {6}}, + {"\U0000094d\U00000308\U00000900", {2381}, {8}}, {"\U0000094d\U0000094d", {2381}, {6}}, {"\U0000094d\U00000308\U0000094d", {2381}, {8}}, {"\U0000094d\U0000200d", {2381}, {6}}, @@ -1147,8 +1057,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000200d\U00000308\U0000000a", {8205, 10}, {5, 6}}, {"\U0000200d\U00000001", {8205, 1}, {3, 4}}, {"\U0000200d\U00000308\U00000001", {8205, 1}, {5, 6}}, - {"\U0000200d\U0000034f", {8205}, {5}}, - {"\U0000200d\U00000308\U0000034f", {8205}, {7}}, + {"\U0000200d\U0000200c", {8205}, {6}}, + {"\U0000200d\U00000308\U0000200c", {8205}, {8}}, {"\U0000200d\U0001f1e6", {8205, 127462}, {3, 7}}, {"\U0000200d\U00000308\U0001f1e6", {8205, 127462}, {5, 9}}, {"\U0000200d\U00000600", {8205, 1536}, {3, 5}}, @@ -1165,8 +1075,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000200d\U00000308\U0000ac00", {8205, 44032}, {5, 8}}, {"\U0000200d\U0000ac01", {8205, 44033}, {3, 6}}, {"\U0000200d\U00000308\U0000ac01", {8205, 44033}, {5, 8}}, - {"\U0000200d\U00000900", {8205}, {6}}, - {"\U0000200d\U00000308\U00000900", {8205}, {8}}, {"\U0000200d\U00000903", {8205}, {6}}, {"\U0000200d\U00000308\U00000903", {8205}, {8}}, {"\U0000200d\U00000904", {8205, 2308}, {3, 6}}, @@ -1179,8 +1087,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000200d\U00000308\U0000231a", {8205, 8986}, {5, 8}}, {"\U0000200d\U00000300", {8205}, {5}}, {"\U0000200d\U00000308\U00000300", {8205}, {7}}, - {"\U0000200d\U0000093c", {8205}, {6}}, - {"\U0000200d\U00000308\U0000093c", {8205}, {8}}, + {"\U0000200d\U00000900", {8205}, {6}}, + {"\U0000200d\U00000308\U00000900", {8205}, {8}}, {"\U0000200d\U0000094d", {8205}, {6}}, {"\U0000200d\U00000308\U0000094d", {8205}, {8}}, {"\U0000200d\U0000200d", {8205}, {6}}, @@ -1195,8 +1103,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000378\U00000308\U0000000a", {888, 10}, {4, 5}}, {"\U00000378\U00000001", {888, 1}, {2, 3}}, {"\U00000378\U00000308\U00000001", {888, 1}, {4, 5}}, - {"\U00000378\U0000034f", {888}, {4}}, - {"\U00000378\U00000308\U0000034f", {888}, {6}}, + {"\U00000378\U0000200c", {888}, {5}}, + {"\U00000378\U00000308\U0000200c", {888}, {7}}, {"\U00000378\U0001f1e6", {888, 127462}, {2, 6}}, {"\U00000378\U00000308\U0001f1e6", {888, 127462}, {4, 8}}, {"\U00000378\U00000600", {888, 1536}, {2, 4}}, @@ -1213,8 +1121,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000378\U00000308\U0000ac00", {888, 44032}, {4, 7}}, {"\U00000378\U0000ac01", {888, 44033}, {2, 5}}, {"\U00000378\U00000308\U0000ac01", {888, 44033}, {4, 7}}, - {"\U00000378\U00000900", {888}, {5}}, - {"\U00000378\U00000308\U00000900", {888}, {7}}, {"\U00000378\U00000903", {888}, {5}}, {"\U00000378\U00000308\U00000903", {888}, {7}}, {"\U00000378\U00000904", {888, 2308}, {2, 5}}, @@ -1227,8 +1133,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000378\U00000308\U0000231a", {888, 8986}, {4, 7}}, {"\U00000378\U00000300", {888}, {4}}, {"\U00000378\U00000308\U00000300", {888}, {6}}, - {"\U00000378\U0000093c", {888}, {5}}, - {"\U00000378\U00000308\U0000093c", {888}, {7}}, + {"\U00000378\U00000900", {888}, {5}}, + {"\U00000378\U00000308\U00000900", {888}, {7}}, {"\U00000378\U0000094d", {888}, {5}}, {"\U00000378\U00000308\U0000094d", {888}, {7}}, {"\U00000378\U0000200d", {888}, {5}}, @@ -1277,7 +1183,7 @@ std::array, 1187> data_utf8 = {{ /// since the size of the code units differ the breaks can contain different /// values. #ifndef TEST_HAS_NO_WIDE_CHARACTERS -std::array, 1187> data_utf16 = {{ +std::array, 1093> data_utf16 = {{ {L"\U00000020\U00000020", {32, 32}, {1, 2}}, {L"\U00000020\U00000308\U00000020", {32, 32}, {2, 3}}, {L"\U00000020\U0000000d", {32, 13}, {1, 2}}, @@ -1286,8 +1192,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000020\U00000308\U0000000a", {32, 10}, {2, 3}}, {L"\U00000020\U00000001", {32, 1}, {1, 2}}, {L"\U00000020\U00000308\U00000001", {32, 1}, {2, 3}}, - {L"\U00000020\U0000034f", {32}, {2}}, - {L"\U00000020\U00000308\U0000034f", {32}, {3}}, + {L"\U00000020\U0000200c", {32}, {2}}, + {L"\U00000020\U00000308\U0000200c", {32}, {3}}, {L"\U00000020\U0001f1e6", {32, 127462}, {1, 3}}, {L"\U00000020\U00000308\U0001f1e6", {32, 127462}, {2, 4}}, {L"\U00000020\U00000600", {32, 1536}, {1, 2}}, @@ -1304,8 +1210,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000020\U00000308\U0000ac00", {32, 44032}, {2, 3}}, {L"\U00000020\U0000ac01", {32, 44033}, {1, 2}}, {L"\U00000020\U00000308\U0000ac01", {32, 44033}, {2, 3}}, - {L"\U00000020\U00000900", {32}, {2}}, - {L"\U00000020\U00000308\U00000900", {32}, {3}}, {L"\U00000020\U00000903", {32}, {2}}, {L"\U00000020\U00000308\U00000903", {32}, {3}}, {L"\U00000020\U00000904", {32, 2308}, {1, 2}}, @@ -1318,8 +1222,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000020\U00000308\U0000231a", {32, 8986}, {2, 3}}, {L"\U00000020\U00000300", {32}, {2}}, {L"\U00000020\U00000308\U00000300", {32}, {3}}, - {L"\U00000020\U0000093c", {32}, {2}}, - {L"\U00000020\U00000308\U0000093c", {32}, {3}}, + {L"\U00000020\U00000900", {32}, {2}}, + {L"\U00000020\U00000308\U00000900", {32}, {3}}, {L"\U00000020\U0000094d", {32}, {2}}, {L"\U00000020\U00000308\U0000094d", {32}, {3}}, {L"\U00000020\U0000200d", {32}, {2}}, @@ -1334,8 +1238,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000d\U00000308\U0000000a", {13, 776, 10}, {1, 2, 3}}, {L"\U0000000d\U00000001", {13, 1}, {1, 2}}, {L"\U0000000d\U00000308\U00000001", {13, 776, 1}, {1, 2, 3}}, - {L"\U0000000d\U0000034f", {13, 847}, {1, 2}}, - {L"\U0000000d\U00000308\U0000034f", {13, 776}, {1, 3}}, + {L"\U0000000d\U0000200c", {13, 8204}, {1, 2}}, + {L"\U0000000d\U00000308\U0000200c", {13, 776}, {1, 3}}, {L"\U0000000d\U0001f1e6", {13, 127462}, {1, 3}}, {L"\U0000000d\U00000308\U0001f1e6", {13, 776, 127462}, {1, 2, 4}}, {L"\U0000000d\U00000600", {13, 1536}, {1, 2}}, @@ -1352,8 +1256,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000d\U00000308\U0000ac00", {13, 776, 44032}, {1, 2, 3}}, {L"\U0000000d\U0000ac01", {13, 44033}, {1, 2}}, {L"\U0000000d\U00000308\U0000ac01", {13, 776, 44033}, {1, 2, 3}}, - {L"\U0000000d\U00000900", {13, 2304}, {1, 2}}, - {L"\U0000000d\U00000308\U00000900", {13, 776}, {1, 3}}, {L"\U0000000d\U00000903", {13, 2307}, {1, 2}}, {L"\U0000000d\U00000308\U00000903", {13, 776}, {1, 3}}, {L"\U0000000d\U00000904", {13, 2308}, {1, 2}}, @@ -1366,8 +1268,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000d\U00000308\U0000231a", {13, 776, 8986}, {1, 2, 3}}, {L"\U0000000d\U00000300", {13, 768}, {1, 2}}, {L"\U0000000d\U00000308\U00000300", {13, 776}, {1, 3}}, - {L"\U0000000d\U0000093c", {13, 2364}, {1, 2}}, - {L"\U0000000d\U00000308\U0000093c", {13, 776}, {1, 3}}, + {L"\U0000000d\U00000900", {13, 2304}, {1, 2}}, + {L"\U0000000d\U00000308\U00000900", {13, 776}, {1, 3}}, {L"\U0000000d\U0000094d", {13, 2381}, {1, 2}}, {L"\U0000000d\U00000308\U0000094d", {13, 776}, {1, 3}}, {L"\U0000000d\U0000200d", {13, 8205}, {1, 2}}, @@ -1382,8 +1284,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000a\U00000308\U0000000a", {10, 776, 10}, {1, 2, 3}}, {L"\U0000000a\U00000001", {10, 1}, {1, 2}}, {L"\U0000000a\U00000308\U00000001", {10, 776, 1}, {1, 2, 3}}, - {L"\U0000000a\U0000034f", {10, 847}, {1, 2}}, - {L"\U0000000a\U00000308\U0000034f", {10, 776}, {1, 3}}, + {L"\U0000000a\U0000200c", {10, 8204}, {1, 2}}, + {L"\U0000000a\U00000308\U0000200c", {10, 776}, {1, 3}}, {L"\U0000000a\U0001f1e6", {10, 127462}, {1, 3}}, {L"\U0000000a\U00000308\U0001f1e6", {10, 776, 127462}, {1, 2, 4}}, {L"\U0000000a\U00000600", {10, 1536}, {1, 2}}, @@ -1400,8 +1302,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000a\U00000308\U0000ac00", {10, 776, 44032}, {1, 2, 3}}, {L"\U0000000a\U0000ac01", {10, 44033}, {1, 2}}, {L"\U0000000a\U00000308\U0000ac01", {10, 776, 44033}, {1, 2, 3}}, - {L"\U0000000a\U00000900", {10, 2304}, {1, 2}}, - {L"\U0000000a\U00000308\U00000900", {10, 776}, {1, 3}}, {L"\U0000000a\U00000903", {10, 2307}, {1, 2}}, {L"\U0000000a\U00000308\U00000903", {10, 776}, {1, 3}}, {L"\U0000000a\U00000904", {10, 2308}, {1, 2}}, @@ -1414,8 +1314,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000a\U00000308\U0000231a", {10, 776, 8986}, {1, 2, 3}}, {L"\U0000000a\U00000300", {10, 768}, {1, 2}}, {L"\U0000000a\U00000308\U00000300", {10, 776}, {1, 3}}, - {L"\U0000000a\U0000093c", {10, 2364}, {1, 2}}, - {L"\U0000000a\U00000308\U0000093c", {10, 776}, {1, 3}}, + {L"\U0000000a\U00000900", {10, 2304}, {1, 2}}, + {L"\U0000000a\U00000308\U00000900", {10, 776}, {1, 3}}, {L"\U0000000a\U0000094d", {10, 2381}, {1, 2}}, {L"\U0000000a\U00000308\U0000094d", {10, 776}, {1, 3}}, {L"\U0000000a\U0000200d", {10, 8205}, {1, 2}}, @@ -1430,8 +1330,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000001\U00000308\U0000000a", {1, 776, 10}, {1, 2, 3}}, {L"\U00000001\U00000001", {1, 1}, {1, 2}}, {L"\U00000001\U00000308\U00000001", {1, 776, 1}, {1, 2, 3}}, - {L"\U00000001\U0000034f", {1, 847}, {1, 2}}, - {L"\U00000001\U00000308\U0000034f", {1, 776}, {1, 3}}, + {L"\U00000001\U0000200c", {1, 8204}, {1, 2}}, + {L"\U00000001\U00000308\U0000200c", {1, 776}, {1, 3}}, {L"\U00000001\U0001f1e6", {1, 127462}, {1, 3}}, {L"\U00000001\U00000308\U0001f1e6", {1, 776, 127462}, {1, 2, 4}}, {L"\U00000001\U00000600", {1, 1536}, {1, 2}}, @@ -1448,8 +1348,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000001\U00000308\U0000ac00", {1, 776, 44032}, {1, 2, 3}}, {L"\U00000001\U0000ac01", {1, 44033}, {1, 2}}, {L"\U00000001\U00000308\U0000ac01", {1, 776, 44033}, {1, 2, 3}}, - {L"\U00000001\U00000900", {1, 2304}, {1, 2}}, - {L"\U00000001\U00000308\U00000900", {1, 776}, {1, 3}}, {L"\U00000001\U00000903", {1, 2307}, {1, 2}}, {L"\U00000001\U00000308\U00000903", {1, 776}, {1, 3}}, {L"\U00000001\U00000904", {1, 2308}, {1, 2}}, @@ -1462,62 +1360,60 @@ std::array, 1187> data_utf16 = {{ {L"\U00000001\U00000308\U0000231a", {1, 776, 8986}, {1, 2, 3}}, {L"\U00000001\U00000300", {1, 768}, {1, 2}}, {L"\U00000001\U00000308\U00000300", {1, 776}, {1, 3}}, - {L"\U00000001\U0000093c", {1, 2364}, {1, 2}}, - {L"\U00000001\U00000308\U0000093c", {1, 776}, {1, 3}}, + {L"\U00000001\U00000900", {1, 2304}, {1, 2}}, + {L"\U00000001\U00000308\U00000900", {1, 776}, {1, 3}}, {L"\U00000001\U0000094d", {1, 2381}, {1, 2}}, {L"\U00000001\U00000308\U0000094d", {1, 776}, {1, 3}}, {L"\U00000001\U0000200d", {1, 8205}, {1, 2}}, {L"\U00000001\U00000308\U0000200d", {1, 776}, {1, 3}}, {L"\U00000001\U00000378", {1, 888}, {1, 2}}, {L"\U00000001\U00000308\U00000378", {1, 776, 888}, {1, 2, 3}}, - {L"\U0000034f\U00000020", {847, 32}, {1, 2}}, - {L"\U0000034f\U00000308\U00000020", {847, 32}, {2, 3}}, - {L"\U0000034f\U0000000d", {847, 13}, {1, 2}}, - {L"\U0000034f\U00000308\U0000000d", {847, 13}, {2, 3}}, - {L"\U0000034f\U0000000a", {847, 10}, {1, 2}}, - {L"\U0000034f\U00000308\U0000000a", {847, 10}, {2, 3}}, - {L"\U0000034f\U00000001", {847, 1}, {1, 2}}, - {L"\U0000034f\U00000308\U00000001", {847, 1}, {2, 3}}, - {L"\U0000034f\U0000034f", {847}, {2}}, - {L"\U0000034f\U00000308\U0000034f", {847}, {3}}, - {L"\U0000034f\U0001f1e6", {847, 127462}, {1, 3}}, - {L"\U0000034f\U00000308\U0001f1e6", {847, 127462}, {2, 4}}, - {L"\U0000034f\U00000600", {847, 1536}, {1, 2}}, - {L"\U0000034f\U00000308\U00000600", {847, 1536}, {2, 3}}, - {L"\U0000034f\U00000a03", {847}, {2}}, - {L"\U0000034f\U00000308\U00000a03", {847}, {3}}, - {L"\U0000034f\U00001100", {847, 4352}, {1, 2}}, - {L"\U0000034f\U00000308\U00001100", {847, 4352}, {2, 3}}, - {L"\U0000034f\U00001160", {847, 4448}, {1, 2}}, - {L"\U0000034f\U00000308\U00001160", {847, 4448}, {2, 3}}, - {L"\U0000034f\U000011a8", {847, 4520}, {1, 2}}, - {L"\U0000034f\U00000308\U000011a8", {847, 4520}, {2, 3}}, - {L"\U0000034f\U0000ac00", {847, 44032}, {1, 2}}, - {L"\U0000034f\U00000308\U0000ac00", {847, 44032}, {2, 3}}, - {L"\U0000034f\U0000ac01", {847, 44033}, {1, 2}}, - {L"\U0000034f\U00000308\U0000ac01", {847, 44033}, {2, 3}}, - {L"\U0000034f\U00000900", {847}, {2}}, - {L"\U0000034f\U00000308\U00000900", {847}, {3}}, - {L"\U0000034f\U00000903", {847}, {2}}, - {L"\U0000034f\U00000308\U00000903", {847}, {3}}, - {L"\U0000034f\U00000904", {847, 2308}, {1, 2}}, - {L"\U0000034f\U00000308\U00000904", {847, 2308}, {2, 3}}, - {L"\U0000034f\U00000d4e", {847, 3406}, {1, 2}}, - {L"\U0000034f\U00000308\U00000d4e", {847, 3406}, {2, 3}}, - {L"\U0000034f\U00000915", {847, 2325}, {1, 2}}, - {L"\U0000034f\U00000308\U00000915", {847, 2325}, {2, 3}}, - {L"\U0000034f\U0000231a", {847, 8986}, {1, 2}}, - {L"\U0000034f\U00000308\U0000231a", {847, 8986}, {2, 3}}, - {L"\U0000034f\U00000300", {847}, {2}}, - {L"\U0000034f\U00000308\U00000300", {847}, {3}}, - {L"\U0000034f\U0000093c", {847}, {2}}, - {L"\U0000034f\U00000308\U0000093c", {847}, {3}}, - {L"\U0000034f\U0000094d", {847}, {2}}, - {L"\U0000034f\U00000308\U0000094d", {847}, {3}}, - {L"\U0000034f\U0000200d", {847}, {2}}, - {L"\U0000034f\U00000308\U0000200d", {847}, {3}}, - {L"\U0000034f\U00000378", {847, 888}, {1, 2}}, - {L"\U0000034f\U00000308\U00000378", {847, 888}, {2, 3}}, + {L"\U0000200c\U00000020", {8204, 32}, {1, 2}}, + {L"\U0000200c\U00000308\U00000020", {8204, 32}, {2, 3}}, + {L"\U0000200c\U0000000d", {8204, 13}, {1, 2}}, + {L"\U0000200c\U00000308\U0000000d", {8204, 13}, {2, 3}}, + {L"\U0000200c\U0000000a", {8204, 10}, {1, 2}}, + {L"\U0000200c\U00000308\U0000000a", {8204, 10}, {2, 3}}, + {L"\U0000200c\U00000001", {8204, 1}, {1, 2}}, + {L"\U0000200c\U00000308\U00000001", {8204, 1}, {2, 3}}, + {L"\U0000200c\U0000200c", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000200c", {8204}, {3}}, + {L"\U0000200c\U0001f1e6", {8204, 127462}, {1, 3}}, + {L"\U0000200c\U00000308\U0001f1e6", {8204, 127462}, {2, 4}}, + {L"\U0000200c\U00000600", {8204, 1536}, {1, 2}}, + {L"\U0000200c\U00000308\U00000600", {8204, 1536}, {2, 3}}, + {L"\U0000200c\U00000a03", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000a03", {8204}, {3}}, + {L"\U0000200c\U00001100", {8204, 4352}, {1, 2}}, + {L"\U0000200c\U00000308\U00001100", {8204, 4352}, {2, 3}}, + {L"\U0000200c\U00001160", {8204, 4448}, {1, 2}}, + {L"\U0000200c\U00000308\U00001160", {8204, 4448}, {2, 3}}, + {L"\U0000200c\U000011a8", {8204, 4520}, {1, 2}}, + {L"\U0000200c\U00000308\U000011a8", {8204, 4520}, {2, 3}}, + {L"\U0000200c\U0000ac00", {8204, 44032}, {1, 2}}, + {L"\U0000200c\U00000308\U0000ac00", {8204, 44032}, {2, 3}}, + {L"\U0000200c\U0000ac01", {8204, 44033}, {1, 2}}, + {L"\U0000200c\U00000308\U0000ac01", {8204, 44033}, {2, 3}}, + {L"\U0000200c\U00000903", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000903", {8204}, {3}}, + {L"\U0000200c\U00000904", {8204, 2308}, {1, 2}}, + {L"\U0000200c\U00000308\U00000904", {8204, 2308}, {2, 3}}, + {L"\U0000200c\U00000d4e", {8204, 3406}, {1, 2}}, + {L"\U0000200c\U00000308\U00000d4e", {8204, 3406}, {2, 3}}, + {L"\U0000200c\U00000915", {8204, 2325}, {1, 2}}, + {L"\U0000200c\U00000308\U00000915", {8204, 2325}, {2, 3}}, + {L"\U0000200c\U0000231a", {8204, 8986}, {1, 2}}, + {L"\U0000200c\U00000308\U0000231a", {8204, 8986}, {2, 3}}, + {L"\U0000200c\U00000300", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000300", {8204}, {3}}, + {L"\U0000200c\U00000900", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000900", {8204}, {3}}, + {L"\U0000200c\U0000094d", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000094d", {8204}, {3}}, + {L"\U0000200c\U0000200d", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000200d", {8204}, {3}}, + {L"\U0000200c\U00000378", {8204, 888}, {1, 2}}, + {L"\U0000200c\U00000308\U00000378", {8204, 888}, {2, 3}}, {L"\U0001f1e6\U00000020", {127462, 32}, {2, 3}}, {L"\U0001f1e6\U00000308\U00000020", {127462, 32}, {3, 4}}, {L"\U0001f1e6\U0000000d", {127462, 13}, {2, 3}}, @@ -1526,8 +1422,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0001f1e6\U00000308\U0000000a", {127462, 10}, {3, 4}}, {L"\U0001f1e6\U00000001", {127462, 1}, {2, 3}}, {L"\U0001f1e6\U00000308\U00000001", {127462, 1}, {3, 4}}, - {L"\U0001f1e6\U0000034f", {127462}, {3}}, - {L"\U0001f1e6\U00000308\U0000034f", {127462}, {4}}, + {L"\U0001f1e6\U0000200c", {127462}, {3}}, + {L"\U0001f1e6\U00000308\U0000200c", {127462}, {4}}, {L"\U0001f1e6\U0001f1e6", {127462}, {4}}, {L"\U0001f1e6\U00000308\U0001f1e6", {127462, 127462}, {3, 5}}, {L"\U0001f1e6\U00000600", {127462, 1536}, {2, 3}}, @@ -1544,8 +1440,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0001f1e6\U00000308\U0000ac00", {127462, 44032}, {3, 4}}, {L"\U0001f1e6\U0000ac01", {127462, 44033}, {2, 3}}, {L"\U0001f1e6\U00000308\U0000ac01", {127462, 44033}, {3, 4}}, - {L"\U0001f1e6\U00000900", {127462}, {3}}, - {L"\U0001f1e6\U00000308\U00000900", {127462}, {4}}, {L"\U0001f1e6\U00000903", {127462}, {3}}, {L"\U0001f1e6\U00000308\U00000903", {127462}, {4}}, {L"\U0001f1e6\U00000904", {127462, 2308}, {2, 3}}, @@ -1558,8 +1452,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0001f1e6\U00000308\U0000231a", {127462, 8986}, {3, 4}}, {L"\U0001f1e6\U00000300", {127462}, {3}}, {L"\U0001f1e6\U00000308\U00000300", {127462}, {4}}, - {L"\U0001f1e6\U0000093c", {127462}, {3}}, - {L"\U0001f1e6\U00000308\U0000093c", {127462}, {4}}, + {L"\U0001f1e6\U00000900", {127462}, {3}}, + {L"\U0001f1e6\U00000308\U00000900", {127462}, {4}}, {L"\U0001f1e6\U0000094d", {127462}, {3}}, {L"\U0001f1e6\U00000308\U0000094d", {127462}, {4}}, {L"\U0001f1e6\U0000200d", {127462}, {3}}, @@ -1574,8 +1468,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000600\U00000308\U0000000a", {1536, 10}, {2, 3}}, {L"\U00000600\U00000001", {1536, 1}, {1, 2}}, {L"\U00000600\U00000308\U00000001", {1536, 1}, {2, 3}}, - {L"\U00000600\U0000034f", {1536}, {2}}, - {L"\U00000600\U00000308\U0000034f", {1536}, {3}}, + {L"\U00000600\U0000200c", {1536}, {2}}, + {L"\U00000600\U00000308\U0000200c", {1536}, {3}}, {L"\U00000600\U0001f1e6", {1536}, {3}}, {L"\U00000600\U00000308\U0001f1e6", {1536, 127462}, {2, 4}}, {L"\U00000600\U00000600", {1536}, {2}}, @@ -1592,8 +1486,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000600\U00000308\U0000ac00", {1536, 44032}, {2, 3}}, {L"\U00000600\U0000ac01", {1536}, {2}}, {L"\U00000600\U00000308\U0000ac01", {1536, 44033}, {2, 3}}, - {L"\U00000600\U00000900", {1536}, {2}}, - {L"\U00000600\U00000308\U00000900", {1536}, {3}}, {L"\U00000600\U00000903", {1536}, {2}}, {L"\U00000600\U00000308\U00000903", {1536}, {3}}, {L"\U00000600\U00000904", {1536}, {2}}, @@ -1606,8 +1498,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000600\U00000308\U0000231a", {1536, 8986}, {2, 3}}, {L"\U00000600\U00000300", {1536}, {2}}, {L"\U00000600\U00000308\U00000300", {1536}, {3}}, - {L"\U00000600\U0000093c", {1536}, {2}}, - {L"\U00000600\U00000308\U0000093c", {1536}, {3}}, + {L"\U00000600\U00000900", {1536}, {2}}, + {L"\U00000600\U00000308\U00000900", {1536}, {3}}, {L"\U00000600\U0000094d", {1536}, {2}}, {L"\U00000600\U00000308\U0000094d", {1536}, {3}}, {L"\U00000600\U0000200d", {1536}, {2}}, @@ -1622,8 +1514,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000a03\U00000308\U0000000a", {2563, 10}, {2, 3}}, {L"\U00000a03\U00000001", {2563, 1}, {1, 2}}, {L"\U00000a03\U00000308\U00000001", {2563, 1}, {2, 3}}, - {L"\U00000a03\U0000034f", {2563}, {2}}, - {L"\U00000a03\U00000308\U0000034f", {2563}, {3}}, + {L"\U00000a03\U0000200c", {2563}, {2}}, + {L"\U00000a03\U00000308\U0000200c", {2563}, {3}}, {L"\U00000a03\U0001f1e6", {2563, 127462}, {1, 3}}, {L"\U00000a03\U00000308\U0001f1e6", {2563, 127462}, {2, 4}}, {L"\U00000a03\U00000600", {2563, 1536}, {1, 2}}, @@ -1640,8 +1532,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000a03\U00000308\U0000ac00", {2563, 44032}, {2, 3}}, {L"\U00000a03\U0000ac01", {2563, 44033}, {1, 2}}, {L"\U00000a03\U00000308\U0000ac01", {2563, 44033}, {2, 3}}, - {L"\U00000a03\U00000900", {2563}, {2}}, - {L"\U00000a03\U00000308\U00000900", {2563}, {3}}, {L"\U00000a03\U00000903", {2563}, {2}}, {L"\U00000a03\U00000308\U00000903", {2563}, {3}}, {L"\U00000a03\U00000904", {2563, 2308}, {1, 2}}, @@ -1654,8 +1544,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000a03\U00000308\U0000231a", {2563, 8986}, {2, 3}}, {L"\U00000a03\U00000300", {2563}, {2}}, {L"\U00000a03\U00000308\U00000300", {2563}, {3}}, - {L"\U00000a03\U0000093c", {2563}, {2}}, - {L"\U00000a03\U00000308\U0000093c", {2563}, {3}}, + {L"\U00000a03\U00000900", {2563}, {2}}, + {L"\U00000a03\U00000308\U00000900", {2563}, {3}}, {L"\U00000a03\U0000094d", {2563}, {2}}, {L"\U00000a03\U00000308\U0000094d", {2563}, {3}}, {L"\U00000a03\U0000200d", {2563}, {2}}, @@ -1670,8 +1560,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00001100\U00000308\U0000000a", {4352, 10}, {2, 3}}, {L"\U00001100\U00000001", {4352, 1}, {1, 2}}, {L"\U00001100\U00000308\U00000001", {4352, 1}, {2, 3}}, - {L"\U00001100\U0000034f", {4352}, {2}}, - {L"\U00001100\U00000308\U0000034f", {4352}, {3}}, + {L"\U00001100\U0000200c", {4352}, {2}}, + {L"\U00001100\U00000308\U0000200c", {4352}, {3}}, {L"\U00001100\U0001f1e6", {4352, 127462}, {1, 3}}, {L"\U00001100\U00000308\U0001f1e6", {4352, 127462}, {2, 4}}, {L"\U00001100\U00000600", {4352, 1536}, {1, 2}}, @@ -1688,8 +1578,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00001100\U00000308\U0000ac00", {4352, 44032}, {2, 3}}, {L"\U00001100\U0000ac01", {4352}, {2}}, {L"\U00001100\U00000308\U0000ac01", {4352, 44033}, {2, 3}}, - {L"\U00001100\U00000900", {4352}, {2}}, - {L"\U00001100\U00000308\U00000900", {4352}, {3}}, {L"\U00001100\U00000903", {4352}, {2}}, {L"\U00001100\U00000308\U00000903", {4352}, {3}}, {L"\U00001100\U00000904", {4352, 2308}, {1, 2}}, @@ -1702,8 +1590,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00001100\U00000308\U0000231a", {4352, 8986}, {2, 3}}, {L"\U00001100\U00000300", {4352}, {2}}, {L"\U00001100\U00000308\U00000300", {4352}, {3}}, - {L"\U00001100\U0000093c", {4352}, {2}}, - {L"\U00001100\U00000308\U0000093c", {4352}, {3}}, + {L"\U00001100\U00000900", {4352}, {2}}, + {L"\U00001100\U00000308\U00000900", {4352}, {3}}, {L"\U00001100\U0000094d", {4352}, {2}}, {L"\U00001100\U00000308\U0000094d", {4352}, {3}}, {L"\U00001100\U0000200d", {4352}, {2}}, @@ -1718,8 +1606,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00001160\U00000308\U0000000a", {4448, 10}, {2, 3}}, {L"\U00001160\U00000001", {4448, 1}, {1, 2}}, {L"\U00001160\U00000308\U00000001", {4448, 1}, {2, 3}}, - {L"\U00001160\U0000034f", {4448}, {2}}, - {L"\U00001160\U00000308\U0000034f", {4448}, {3}}, + {L"\U00001160\U0000200c", {4448}, {2}}, + {L"\U00001160\U00000308\U0000200c", {4448}, {3}}, {L"\U00001160\U0001f1e6", {4448, 127462}, {1, 3}}, {L"\U00001160\U00000308\U0001f1e6", {4448, 127462}, {2, 4}}, {L"\U00001160\U00000600", {4448, 1536}, {1, 2}}, @@ -1736,8 +1624,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00001160\U00000308\U0000ac00", {4448, 44032}, {2, 3}}, {L"\U00001160\U0000ac01", {4448, 44033}, {1, 2}}, {L"\U00001160\U00000308\U0000ac01", {4448, 44033}, {2, 3}}, - {L"\U00001160\U00000900", {4448}, {2}}, - {L"\U00001160\U00000308\U00000900", {4448}, {3}}, {L"\U00001160\U00000903", {4448}, {2}}, {L"\U00001160\U00000308\U00000903", {4448}, {3}}, {L"\U00001160\U00000904", {4448, 2308}, {1, 2}}, @@ -1750,8 +1636,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00001160\U00000308\U0000231a", {4448, 8986}, {2, 3}}, {L"\U00001160\U00000300", {4448}, {2}}, {L"\U00001160\U00000308\U00000300", {4448}, {3}}, - {L"\U00001160\U0000093c", {4448}, {2}}, - {L"\U00001160\U00000308\U0000093c", {4448}, {3}}, + {L"\U00001160\U00000900", {4448}, {2}}, + {L"\U00001160\U00000308\U00000900", {4448}, {3}}, {L"\U00001160\U0000094d", {4448}, {2}}, {L"\U00001160\U00000308\U0000094d", {4448}, {3}}, {L"\U00001160\U0000200d", {4448}, {2}}, @@ -1766,8 +1652,8 @@ std::array, 1187> data_utf16 = {{ {L"\U000011a8\U00000308\U0000000a", {4520, 10}, {2, 3}}, {L"\U000011a8\U00000001", {4520, 1}, {1, 2}}, {L"\U000011a8\U00000308\U00000001", {4520, 1}, {2, 3}}, - {L"\U000011a8\U0000034f", {4520}, {2}}, - {L"\U000011a8\U00000308\U0000034f", {4520}, {3}}, + {L"\U000011a8\U0000200c", {4520}, {2}}, + {L"\U000011a8\U00000308\U0000200c", {4520}, {3}}, {L"\U000011a8\U0001f1e6", {4520, 127462}, {1, 3}}, {L"\U000011a8\U00000308\U0001f1e6", {4520, 127462}, {2, 4}}, {L"\U000011a8\U00000600", {4520, 1536}, {1, 2}}, @@ -1784,8 +1670,6 @@ std::array, 1187> data_utf16 = {{ {L"\U000011a8\U00000308\U0000ac00", {4520, 44032}, {2, 3}}, {L"\U000011a8\U0000ac01", {4520, 44033}, {1, 2}}, {L"\U000011a8\U00000308\U0000ac01", {4520, 44033}, {2, 3}}, - {L"\U000011a8\U00000900", {4520}, {2}}, - {L"\U000011a8\U00000308\U00000900", {4520}, {3}}, {L"\U000011a8\U00000903", {4520}, {2}}, {L"\U000011a8\U00000308\U00000903", {4520}, {3}}, {L"\U000011a8\U00000904", {4520, 2308}, {1, 2}}, @@ -1798,8 +1682,8 @@ std::array, 1187> data_utf16 = {{ {L"\U000011a8\U00000308\U0000231a", {4520, 8986}, {2, 3}}, {L"\U000011a8\U00000300", {4520}, {2}}, {L"\U000011a8\U00000308\U00000300", {4520}, {3}}, - {L"\U000011a8\U0000093c", {4520}, {2}}, - {L"\U000011a8\U00000308\U0000093c", {4520}, {3}}, + {L"\U000011a8\U00000900", {4520}, {2}}, + {L"\U000011a8\U00000308\U00000900", {4520}, {3}}, {L"\U000011a8\U0000094d", {4520}, {2}}, {L"\U000011a8\U00000308\U0000094d", {4520}, {3}}, {L"\U000011a8\U0000200d", {4520}, {2}}, @@ -1814,8 +1698,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac00\U00000308\U0000000a", {44032, 10}, {2, 3}}, {L"\U0000ac00\U00000001", {44032, 1}, {1, 2}}, {L"\U0000ac00\U00000308\U00000001", {44032, 1}, {2, 3}}, - {L"\U0000ac00\U0000034f", {44032}, {2}}, - {L"\U0000ac00\U00000308\U0000034f", {44032}, {3}}, + {L"\U0000ac00\U0000200c", {44032}, {2}}, + {L"\U0000ac00\U00000308\U0000200c", {44032}, {3}}, {L"\U0000ac00\U0001f1e6", {44032, 127462}, {1, 3}}, {L"\U0000ac00\U00000308\U0001f1e6", {44032, 127462}, {2, 4}}, {L"\U0000ac00\U00000600", {44032, 1536}, {1, 2}}, @@ -1832,8 +1716,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac00\U00000308\U0000ac00", {44032, 44032}, {2, 3}}, {L"\U0000ac00\U0000ac01", {44032, 44033}, {1, 2}}, {L"\U0000ac00\U00000308\U0000ac01", {44032, 44033}, {2, 3}}, - {L"\U0000ac00\U00000900", {44032}, {2}}, - {L"\U0000ac00\U00000308\U00000900", {44032}, {3}}, {L"\U0000ac00\U00000903", {44032}, {2}}, {L"\U0000ac00\U00000308\U00000903", {44032}, {3}}, {L"\U0000ac00\U00000904", {44032, 2308}, {1, 2}}, @@ -1846,8 +1728,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac00\U00000308\U0000231a", {44032, 8986}, {2, 3}}, {L"\U0000ac00\U00000300", {44032}, {2}}, {L"\U0000ac00\U00000308\U00000300", {44032}, {3}}, - {L"\U0000ac00\U0000093c", {44032}, {2}}, - {L"\U0000ac00\U00000308\U0000093c", {44032}, {3}}, + {L"\U0000ac00\U00000900", {44032}, {2}}, + {L"\U0000ac00\U00000308\U00000900", {44032}, {3}}, {L"\U0000ac00\U0000094d", {44032}, {2}}, {L"\U0000ac00\U00000308\U0000094d", {44032}, {3}}, {L"\U0000ac00\U0000200d", {44032}, {2}}, @@ -1862,8 +1744,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac01\U00000308\U0000000a", {44033, 10}, {2, 3}}, {L"\U0000ac01\U00000001", {44033, 1}, {1, 2}}, {L"\U0000ac01\U00000308\U00000001", {44033, 1}, {2, 3}}, - {L"\U0000ac01\U0000034f", {44033}, {2}}, - {L"\U0000ac01\U00000308\U0000034f", {44033}, {3}}, + {L"\U0000ac01\U0000200c", {44033}, {2}}, + {L"\U0000ac01\U00000308\U0000200c", {44033}, {3}}, {L"\U0000ac01\U0001f1e6", {44033, 127462}, {1, 3}}, {L"\U0000ac01\U00000308\U0001f1e6", {44033, 127462}, {2, 4}}, {L"\U0000ac01\U00000600", {44033, 1536}, {1, 2}}, @@ -1880,8 +1762,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac01\U00000308\U0000ac00", {44033, 44032}, {2, 3}}, {L"\U0000ac01\U0000ac01", {44033, 44033}, {1, 2}}, {L"\U0000ac01\U00000308\U0000ac01", {44033, 44033}, {2, 3}}, - {L"\U0000ac01\U00000900", {44033}, {2}}, - {L"\U0000ac01\U00000308\U00000900", {44033}, {3}}, {L"\U0000ac01\U00000903", {44033}, {2}}, {L"\U0000ac01\U00000308\U00000903", {44033}, {3}}, {L"\U0000ac01\U00000904", {44033, 2308}, {1, 2}}, @@ -1894,62 +1774,14 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac01\U00000308\U0000231a", {44033, 8986}, {2, 3}}, {L"\U0000ac01\U00000300", {44033}, {2}}, {L"\U0000ac01\U00000308\U00000300", {44033}, {3}}, - {L"\U0000ac01\U0000093c", {44033}, {2}}, - {L"\U0000ac01\U00000308\U0000093c", {44033}, {3}}, + {L"\U0000ac01\U00000900", {44033}, {2}}, + {L"\U0000ac01\U00000308\U00000900", {44033}, {3}}, {L"\U0000ac01\U0000094d", {44033}, {2}}, {L"\U0000ac01\U00000308\U0000094d", {44033}, {3}}, {L"\U0000ac01\U0000200d", {44033}, {2}}, {L"\U0000ac01\U00000308\U0000200d", {44033}, {3}}, {L"\U0000ac01\U00000378", {44033, 888}, {1, 2}}, {L"\U0000ac01\U00000308\U00000378", {44033, 888}, {2, 3}}, - {L"\U00000900\U00000020", {2304, 32}, {1, 2}}, - {L"\U00000900\U00000308\U00000020", {2304, 32}, {2, 3}}, - {L"\U00000900\U0000000d", {2304, 13}, {1, 2}}, - {L"\U00000900\U00000308\U0000000d", {2304, 13}, {2, 3}}, - {L"\U00000900\U0000000a", {2304, 10}, {1, 2}}, - {L"\U00000900\U00000308\U0000000a", {2304, 10}, {2, 3}}, - {L"\U00000900\U00000001", {2304, 1}, {1, 2}}, - {L"\U00000900\U00000308\U00000001", {2304, 1}, {2, 3}}, - {L"\U00000900\U0000034f", {2304}, {2}}, - {L"\U00000900\U00000308\U0000034f", {2304}, {3}}, - {L"\U00000900\U0001f1e6", {2304, 127462}, {1, 3}}, - {L"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {2, 4}}, - {L"\U00000900\U00000600", {2304, 1536}, {1, 2}}, - {L"\U00000900\U00000308\U00000600", {2304, 1536}, {2, 3}}, - {L"\U00000900\U00000a03", {2304}, {2}}, - {L"\U00000900\U00000308\U00000a03", {2304}, {3}}, - {L"\U00000900\U00001100", {2304, 4352}, {1, 2}}, - {L"\U00000900\U00000308\U00001100", {2304, 4352}, {2, 3}}, - {L"\U00000900\U00001160", {2304, 4448}, {1, 2}}, - {L"\U00000900\U00000308\U00001160", {2304, 4448}, {2, 3}}, - {L"\U00000900\U000011a8", {2304, 4520}, {1, 2}}, - {L"\U00000900\U00000308\U000011a8", {2304, 4520}, {2, 3}}, - {L"\U00000900\U0000ac00", {2304, 44032}, {1, 2}}, - {L"\U00000900\U00000308\U0000ac00", {2304, 44032}, {2, 3}}, - {L"\U00000900\U0000ac01", {2304, 44033}, {1, 2}}, - {L"\U00000900\U00000308\U0000ac01", {2304, 44033}, {2, 3}}, - {L"\U00000900\U00000900", {2304}, {2}}, - {L"\U00000900\U00000308\U00000900", {2304}, {3}}, - {L"\U00000900\U00000903", {2304}, {2}}, - {L"\U00000900\U00000308\U00000903", {2304}, {3}}, - {L"\U00000900\U00000904", {2304, 2308}, {1, 2}}, - {L"\U00000900\U00000308\U00000904", {2304, 2308}, {2, 3}}, - {L"\U00000900\U00000d4e", {2304, 3406}, {1, 2}}, - {L"\U00000900\U00000308\U00000d4e", {2304, 3406}, {2, 3}}, - {L"\U00000900\U00000915", {2304, 2325}, {1, 2}}, - {L"\U00000900\U00000308\U00000915", {2304, 2325}, {2, 3}}, - {L"\U00000900\U0000231a", {2304, 8986}, {1, 2}}, - {L"\U00000900\U00000308\U0000231a", {2304, 8986}, {2, 3}}, - {L"\U00000900\U00000300", {2304}, {2}}, - {L"\U00000900\U00000308\U00000300", {2304}, {3}}, - {L"\U00000900\U0000093c", {2304}, {2}}, - {L"\U00000900\U00000308\U0000093c", {2304}, {3}}, - {L"\U00000900\U0000094d", {2304}, {2}}, - {L"\U00000900\U00000308\U0000094d", {2304}, {3}}, - {L"\U00000900\U0000200d", {2304}, {2}}, - {L"\U00000900\U00000308\U0000200d", {2304}, {3}}, - {L"\U00000900\U00000378", {2304, 888}, {1, 2}}, - {L"\U00000900\U00000308\U00000378", {2304, 888}, {2, 3}}, {L"\U00000903\U00000020", {2307, 32}, {1, 2}}, {L"\U00000903\U00000308\U00000020", {2307, 32}, {2, 3}}, {L"\U00000903\U0000000d", {2307, 13}, {1, 2}}, @@ -1958,8 +1790,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000903\U00000308\U0000000a", {2307, 10}, {2, 3}}, {L"\U00000903\U00000001", {2307, 1}, {1, 2}}, {L"\U00000903\U00000308\U00000001", {2307, 1}, {2, 3}}, - {L"\U00000903\U0000034f", {2307}, {2}}, - {L"\U00000903\U00000308\U0000034f", {2307}, {3}}, + {L"\U00000903\U0000200c", {2307}, {2}}, + {L"\U00000903\U00000308\U0000200c", {2307}, {3}}, {L"\U00000903\U0001f1e6", {2307, 127462}, {1, 3}}, {L"\U00000903\U00000308\U0001f1e6", {2307, 127462}, {2, 4}}, {L"\U00000903\U00000600", {2307, 1536}, {1, 2}}, @@ -1976,8 +1808,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000903\U00000308\U0000ac00", {2307, 44032}, {2, 3}}, {L"\U00000903\U0000ac01", {2307, 44033}, {1, 2}}, {L"\U00000903\U00000308\U0000ac01", {2307, 44033}, {2, 3}}, - {L"\U00000903\U00000900", {2307}, {2}}, - {L"\U00000903\U00000308\U00000900", {2307}, {3}}, {L"\U00000903\U00000903", {2307}, {2}}, {L"\U00000903\U00000308\U00000903", {2307}, {3}}, {L"\U00000903\U00000904", {2307, 2308}, {1, 2}}, @@ -1990,8 +1820,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000903\U00000308\U0000231a", {2307, 8986}, {2, 3}}, {L"\U00000903\U00000300", {2307}, {2}}, {L"\U00000903\U00000308\U00000300", {2307}, {3}}, - {L"\U00000903\U0000093c", {2307}, {2}}, - {L"\U00000903\U00000308\U0000093c", {2307}, {3}}, + {L"\U00000903\U00000900", {2307}, {2}}, + {L"\U00000903\U00000308\U00000900", {2307}, {3}}, {L"\U00000903\U0000094d", {2307}, {2}}, {L"\U00000903\U00000308\U0000094d", {2307}, {3}}, {L"\U00000903\U0000200d", {2307}, {2}}, @@ -2006,8 +1836,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000904\U00000308\U0000000a", {2308, 10}, {2, 3}}, {L"\U00000904\U00000001", {2308, 1}, {1, 2}}, {L"\U00000904\U00000308\U00000001", {2308, 1}, {2, 3}}, - {L"\U00000904\U0000034f", {2308}, {2}}, - {L"\U00000904\U00000308\U0000034f", {2308}, {3}}, + {L"\U00000904\U0000200c", {2308}, {2}}, + {L"\U00000904\U00000308\U0000200c", {2308}, {3}}, {L"\U00000904\U0001f1e6", {2308, 127462}, {1, 3}}, {L"\U00000904\U00000308\U0001f1e6", {2308, 127462}, {2, 4}}, {L"\U00000904\U00000600", {2308, 1536}, {1, 2}}, @@ -2024,8 +1854,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000904\U00000308\U0000ac00", {2308, 44032}, {2, 3}}, {L"\U00000904\U0000ac01", {2308, 44033}, {1, 2}}, {L"\U00000904\U00000308\U0000ac01", {2308, 44033}, {2, 3}}, - {L"\U00000904\U00000900", {2308}, {2}}, - {L"\U00000904\U00000308\U00000900", {2308}, {3}}, {L"\U00000904\U00000903", {2308}, {2}}, {L"\U00000904\U00000308\U00000903", {2308}, {3}}, {L"\U00000904\U00000904", {2308, 2308}, {1, 2}}, @@ -2038,8 +1866,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000904\U00000308\U0000231a", {2308, 8986}, {2, 3}}, {L"\U00000904\U00000300", {2308}, {2}}, {L"\U00000904\U00000308\U00000300", {2308}, {3}}, - {L"\U00000904\U0000093c", {2308}, {2}}, - {L"\U00000904\U00000308\U0000093c", {2308}, {3}}, + {L"\U00000904\U00000900", {2308}, {2}}, + {L"\U00000904\U00000308\U00000900", {2308}, {3}}, {L"\U00000904\U0000094d", {2308}, {2}}, {L"\U00000904\U00000308\U0000094d", {2308}, {3}}, {L"\U00000904\U0000200d", {2308}, {2}}, @@ -2054,8 +1882,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000d4e\U00000308\U0000000a", {3406, 10}, {2, 3}}, {L"\U00000d4e\U00000001", {3406, 1}, {1, 2}}, {L"\U00000d4e\U00000308\U00000001", {3406, 1}, {2, 3}}, - {L"\U00000d4e\U0000034f", {3406}, {2}}, - {L"\U00000d4e\U00000308\U0000034f", {3406}, {3}}, + {L"\U00000d4e\U0000200c", {3406}, {2}}, + {L"\U00000d4e\U00000308\U0000200c", {3406}, {3}}, {L"\U00000d4e\U0001f1e6", {3406}, {3}}, {L"\U00000d4e\U00000308\U0001f1e6", {3406, 127462}, {2, 4}}, {L"\U00000d4e\U00000600", {3406}, {2}}, @@ -2072,8 +1900,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000d4e\U00000308\U0000ac00", {3406, 44032}, {2, 3}}, {L"\U00000d4e\U0000ac01", {3406}, {2}}, {L"\U00000d4e\U00000308\U0000ac01", {3406, 44033}, {2, 3}}, - {L"\U00000d4e\U00000900", {3406}, {2}}, - {L"\U00000d4e\U00000308\U00000900", {3406}, {3}}, {L"\U00000d4e\U00000903", {3406}, {2}}, {L"\U00000d4e\U00000308\U00000903", {3406}, {3}}, {L"\U00000d4e\U00000904", {3406}, {2}}, @@ -2086,8 +1912,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000d4e\U00000308\U0000231a", {3406, 8986}, {2, 3}}, {L"\U00000d4e\U00000300", {3406}, {2}}, {L"\U00000d4e\U00000308\U00000300", {3406}, {3}}, - {L"\U00000d4e\U0000093c", {3406}, {2}}, - {L"\U00000d4e\U00000308\U0000093c", {3406}, {3}}, + {L"\U00000d4e\U00000900", {3406}, {2}}, + {L"\U00000d4e\U00000308\U00000900", {3406}, {3}}, {L"\U00000d4e\U0000094d", {3406}, {2}}, {L"\U00000d4e\U00000308\U0000094d", {3406}, {3}}, {L"\U00000d4e\U0000200d", {3406}, {2}}, @@ -2102,8 +1928,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000915\U00000308\U0000000a", {2325, 10}, {2, 3}}, {L"\U00000915\U00000001", {2325, 1}, {1, 2}}, {L"\U00000915\U00000308\U00000001", {2325, 1}, {2, 3}}, - {L"\U00000915\U0000034f", {2325}, {2}}, - {L"\U00000915\U00000308\U0000034f", {2325}, {3}}, + {L"\U00000915\U0000200c", {2325}, {2}}, + {L"\U00000915\U00000308\U0000200c", {2325}, {3}}, {L"\U00000915\U0001f1e6", {2325, 127462}, {1, 3}}, {L"\U00000915\U00000308\U0001f1e6", {2325, 127462}, {2, 4}}, {L"\U00000915\U00000600", {2325, 1536}, {1, 2}}, @@ -2120,8 +1946,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000915\U00000308\U0000ac00", {2325, 44032}, {2, 3}}, {L"\U00000915\U0000ac01", {2325, 44033}, {1, 2}}, {L"\U00000915\U00000308\U0000ac01", {2325, 44033}, {2, 3}}, - {L"\U00000915\U00000900", {2325}, {2}}, - {L"\U00000915\U00000308\U00000900", {2325}, {3}}, {L"\U00000915\U00000903", {2325}, {2}}, {L"\U00000915\U00000308\U00000903", {2325}, {3}}, {L"\U00000915\U00000904", {2325, 2308}, {1, 2}}, @@ -2134,8 +1958,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000915\U00000308\U0000231a", {2325, 8986}, {2, 3}}, {L"\U00000915\U00000300", {2325}, {2}}, {L"\U00000915\U00000308\U00000300", {2325}, {3}}, - {L"\U00000915\U0000093c", {2325}, {2}}, - {L"\U00000915\U00000308\U0000093c", {2325}, {3}}, + {L"\U00000915\U00000900", {2325}, {2}}, + {L"\U00000915\U00000308\U00000900", {2325}, {3}}, {L"\U00000915\U0000094d", {2325}, {2}}, {L"\U00000915\U00000308\U0000094d", {2325}, {3}}, {L"\U00000915\U0000200d", {2325}, {2}}, @@ -2150,8 +1974,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000231a\U00000308\U0000000a", {8986, 10}, {2, 3}}, {L"\U0000231a\U00000001", {8986, 1}, {1, 2}}, {L"\U0000231a\U00000308\U00000001", {8986, 1}, {2, 3}}, - {L"\U0000231a\U0000034f", {8986}, {2}}, - {L"\U0000231a\U00000308\U0000034f", {8986}, {3}}, + {L"\U0000231a\U0000200c", {8986}, {2}}, + {L"\U0000231a\U00000308\U0000200c", {8986}, {3}}, {L"\U0000231a\U0001f1e6", {8986, 127462}, {1, 3}}, {L"\U0000231a\U00000308\U0001f1e6", {8986, 127462}, {2, 4}}, {L"\U0000231a\U00000600", {8986, 1536}, {1, 2}}, @@ -2168,8 +1992,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000231a\U00000308\U0000ac00", {8986, 44032}, {2, 3}}, {L"\U0000231a\U0000ac01", {8986, 44033}, {1, 2}}, {L"\U0000231a\U00000308\U0000ac01", {8986, 44033}, {2, 3}}, - {L"\U0000231a\U00000900", {8986}, {2}}, - {L"\U0000231a\U00000308\U00000900", {8986}, {3}}, {L"\U0000231a\U00000903", {8986}, {2}}, {L"\U0000231a\U00000308\U00000903", {8986}, {3}}, {L"\U0000231a\U00000904", {8986, 2308}, {1, 2}}, @@ -2182,8 +2004,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000231a\U00000308\U0000231a", {8986, 8986}, {2, 3}}, {L"\U0000231a\U00000300", {8986}, {2}}, {L"\U0000231a\U00000308\U00000300", {8986}, {3}}, - {L"\U0000231a\U0000093c", {8986}, {2}}, - {L"\U0000231a\U00000308\U0000093c", {8986}, {3}}, + {L"\U0000231a\U00000900", {8986}, {2}}, + {L"\U0000231a\U00000308\U00000900", {8986}, {3}}, {L"\U0000231a\U0000094d", {8986}, {2}}, {L"\U0000231a\U00000308\U0000094d", {8986}, {3}}, {L"\U0000231a\U0000200d", {8986}, {2}}, @@ -2198,8 +2020,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000300\U00000308\U0000000a", {768, 10}, {2, 3}}, {L"\U00000300\U00000001", {768, 1}, {1, 2}}, {L"\U00000300\U00000308\U00000001", {768, 1}, {2, 3}}, - {L"\U00000300\U0000034f", {768}, {2}}, - {L"\U00000300\U00000308\U0000034f", {768}, {3}}, + {L"\U00000300\U0000200c", {768}, {2}}, + {L"\U00000300\U00000308\U0000200c", {768}, {3}}, {L"\U00000300\U0001f1e6", {768, 127462}, {1, 3}}, {L"\U00000300\U00000308\U0001f1e6", {768, 127462}, {2, 4}}, {L"\U00000300\U00000600", {768, 1536}, {1, 2}}, @@ -2216,8 +2038,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000300\U00000308\U0000ac00", {768, 44032}, {2, 3}}, {L"\U00000300\U0000ac01", {768, 44033}, {1, 2}}, {L"\U00000300\U00000308\U0000ac01", {768, 44033}, {2, 3}}, - {L"\U00000300\U00000900", {768}, {2}}, - {L"\U00000300\U00000308\U00000900", {768}, {3}}, {L"\U00000300\U00000903", {768}, {2}}, {L"\U00000300\U00000308\U00000903", {768}, {3}}, {L"\U00000300\U00000904", {768, 2308}, {1, 2}}, @@ -2230,62 +2050,60 @@ std::array, 1187> data_utf16 = {{ {L"\U00000300\U00000308\U0000231a", {768, 8986}, {2, 3}}, {L"\U00000300\U00000300", {768}, {2}}, {L"\U00000300\U00000308\U00000300", {768}, {3}}, - {L"\U00000300\U0000093c", {768}, {2}}, - {L"\U00000300\U00000308\U0000093c", {768}, {3}}, + {L"\U00000300\U00000900", {768}, {2}}, + {L"\U00000300\U00000308\U00000900", {768}, {3}}, {L"\U00000300\U0000094d", {768}, {2}}, {L"\U00000300\U00000308\U0000094d", {768}, {3}}, {L"\U00000300\U0000200d", {768}, {2}}, {L"\U00000300\U00000308\U0000200d", {768}, {3}}, {L"\U00000300\U00000378", {768, 888}, {1, 2}}, {L"\U00000300\U00000308\U00000378", {768, 888}, {2, 3}}, - {L"\U0000093c\U00000020", {2364, 32}, {1, 2}}, - {L"\U0000093c\U00000308\U00000020", {2364, 32}, {2, 3}}, - {L"\U0000093c\U0000000d", {2364, 13}, {1, 2}}, - {L"\U0000093c\U00000308\U0000000d", {2364, 13}, {2, 3}}, - {L"\U0000093c\U0000000a", {2364, 10}, {1, 2}}, - {L"\U0000093c\U00000308\U0000000a", {2364, 10}, {2, 3}}, - {L"\U0000093c\U00000001", {2364, 1}, {1, 2}}, - {L"\U0000093c\U00000308\U00000001", {2364, 1}, {2, 3}}, - {L"\U0000093c\U0000034f", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000034f", {2364}, {3}}, - {L"\U0000093c\U0001f1e6", {2364, 127462}, {1, 3}}, - {L"\U0000093c\U00000308\U0001f1e6", {2364, 127462}, {2, 4}}, - {L"\U0000093c\U00000600", {2364, 1536}, {1, 2}}, - {L"\U0000093c\U00000308\U00000600", {2364, 1536}, {2, 3}}, - {L"\U0000093c\U00000a03", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000a03", {2364}, {3}}, - {L"\U0000093c\U00001100", {2364, 4352}, {1, 2}}, - {L"\U0000093c\U00000308\U00001100", {2364, 4352}, {2, 3}}, - {L"\U0000093c\U00001160", {2364, 4448}, {1, 2}}, - {L"\U0000093c\U00000308\U00001160", {2364, 4448}, {2, 3}}, - {L"\U0000093c\U000011a8", {2364, 4520}, {1, 2}}, - {L"\U0000093c\U00000308\U000011a8", {2364, 4520}, {2, 3}}, - {L"\U0000093c\U0000ac00", {2364, 44032}, {1, 2}}, - {L"\U0000093c\U00000308\U0000ac00", {2364, 44032}, {2, 3}}, - {L"\U0000093c\U0000ac01", {2364, 44033}, {1, 2}}, - {L"\U0000093c\U00000308\U0000ac01", {2364, 44033}, {2, 3}}, - {L"\U0000093c\U00000900", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000900", {2364}, {3}}, - {L"\U0000093c\U00000903", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000903", {2364}, {3}}, - {L"\U0000093c\U00000904", {2364, 2308}, {1, 2}}, - {L"\U0000093c\U00000308\U00000904", {2364, 2308}, {2, 3}}, - {L"\U0000093c\U00000d4e", {2364, 3406}, {1, 2}}, - {L"\U0000093c\U00000308\U00000d4e", {2364, 3406}, {2, 3}}, - {L"\U0000093c\U00000915", {2364, 2325}, {1, 2}}, - {L"\U0000093c\U00000308\U00000915", {2364, 2325}, {2, 3}}, - {L"\U0000093c\U0000231a", {2364, 8986}, {1, 2}}, - {L"\U0000093c\U00000308\U0000231a", {2364, 8986}, {2, 3}}, - {L"\U0000093c\U00000300", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000300", {2364}, {3}}, - {L"\U0000093c\U0000093c", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000093c", {2364}, {3}}, - {L"\U0000093c\U0000094d", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000094d", {2364}, {3}}, - {L"\U0000093c\U0000200d", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000200d", {2364}, {3}}, - {L"\U0000093c\U00000378", {2364, 888}, {1, 2}}, - {L"\U0000093c\U00000308\U00000378", {2364, 888}, {2, 3}}, + {L"\U00000900\U00000020", {2304, 32}, {1, 2}}, + {L"\U00000900\U00000308\U00000020", {2304, 32}, {2, 3}}, + {L"\U00000900\U0000000d", {2304, 13}, {1, 2}}, + {L"\U00000900\U00000308\U0000000d", {2304, 13}, {2, 3}}, + {L"\U00000900\U0000000a", {2304, 10}, {1, 2}}, + {L"\U00000900\U00000308\U0000000a", {2304, 10}, {2, 3}}, + {L"\U00000900\U00000001", {2304, 1}, {1, 2}}, + {L"\U00000900\U00000308\U00000001", {2304, 1}, {2, 3}}, + {L"\U00000900\U0000200c", {2304}, {2}}, + {L"\U00000900\U00000308\U0000200c", {2304}, {3}}, + {L"\U00000900\U0001f1e6", {2304, 127462}, {1, 3}}, + {L"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {2, 4}}, + {L"\U00000900\U00000600", {2304, 1536}, {1, 2}}, + {L"\U00000900\U00000308\U00000600", {2304, 1536}, {2, 3}}, + {L"\U00000900\U00000a03", {2304}, {2}}, + {L"\U00000900\U00000308\U00000a03", {2304}, {3}}, + {L"\U00000900\U00001100", {2304, 4352}, {1, 2}}, + {L"\U00000900\U00000308\U00001100", {2304, 4352}, {2, 3}}, + {L"\U00000900\U00001160", {2304, 4448}, {1, 2}}, + {L"\U00000900\U00000308\U00001160", {2304, 4448}, {2, 3}}, + {L"\U00000900\U000011a8", {2304, 4520}, {1, 2}}, + {L"\U00000900\U00000308\U000011a8", {2304, 4520}, {2, 3}}, + {L"\U00000900\U0000ac00", {2304, 44032}, {1, 2}}, + {L"\U00000900\U00000308\U0000ac00", {2304, 44032}, {2, 3}}, + {L"\U00000900\U0000ac01", {2304, 44033}, {1, 2}}, + {L"\U00000900\U00000308\U0000ac01", {2304, 44033}, {2, 3}}, + {L"\U00000900\U00000903", {2304}, {2}}, + {L"\U00000900\U00000308\U00000903", {2304}, {3}}, + {L"\U00000900\U00000904", {2304, 2308}, {1, 2}}, + {L"\U00000900\U00000308\U00000904", {2304, 2308}, {2, 3}}, + {L"\U00000900\U00000d4e", {2304, 3406}, {1, 2}}, + {L"\U00000900\U00000308\U00000d4e", {2304, 3406}, {2, 3}}, + {L"\U00000900\U00000915", {2304, 2325}, {1, 2}}, + {L"\U00000900\U00000308\U00000915", {2304, 2325}, {2, 3}}, + {L"\U00000900\U0000231a", {2304, 8986}, {1, 2}}, + {L"\U00000900\U00000308\U0000231a", {2304, 8986}, {2, 3}}, + {L"\U00000900\U00000300", {2304}, {2}}, + {L"\U00000900\U00000308\U00000300", {2304}, {3}}, + {L"\U00000900\U00000900", {2304}, {2}}, + {L"\U00000900\U00000308\U00000900", {2304}, {3}}, + {L"\U00000900\U0000094d", {2304}, {2}}, + {L"\U00000900\U00000308\U0000094d", {2304}, {3}}, + {L"\U00000900\U0000200d", {2304}, {2}}, + {L"\U00000900\U00000308\U0000200d", {2304}, {3}}, + {L"\U00000900\U00000378", {2304, 888}, {1, 2}}, + {L"\U00000900\U00000308\U00000378", {2304, 888}, {2, 3}}, {L"\U0000094d\U00000020", {2381, 32}, {1, 2}}, {L"\U0000094d\U00000308\U00000020", {2381, 32}, {2, 3}}, {L"\U0000094d\U0000000d", {2381, 13}, {1, 2}}, @@ -2294,8 +2112,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000094d\U00000308\U0000000a", {2381, 10}, {2, 3}}, {L"\U0000094d\U00000001", {2381, 1}, {1, 2}}, {L"\U0000094d\U00000308\U00000001", {2381, 1}, {2, 3}}, - {L"\U0000094d\U0000034f", {2381}, {2}}, - {L"\U0000094d\U00000308\U0000034f", {2381}, {3}}, + {L"\U0000094d\U0000200c", {2381}, {2}}, + {L"\U0000094d\U00000308\U0000200c", {2381}, {3}}, {L"\U0000094d\U0001f1e6", {2381, 127462}, {1, 3}}, {L"\U0000094d\U00000308\U0001f1e6", {2381, 127462}, {2, 4}}, {L"\U0000094d\U00000600", {2381, 1536}, {1, 2}}, @@ -2312,8 +2130,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000094d\U00000308\U0000ac00", {2381, 44032}, {2, 3}}, {L"\U0000094d\U0000ac01", {2381, 44033}, {1, 2}}, {L"\U0000094d\U00000308\U0000ac01", {2381, 44033}, {2, 3}}, - {L"\U0000094d\U00000900", {2381}, {2}}, - {L"\U0000094d\U00000308\U00000900", {2381}, {3}}, {L"\U0000094d\U00000903", {2381}, {2}}, {L"\U0000094d\U00000308\U00000903", {2381}, {3}}, {L"\U0000094d\U00000904", {2381, 2308}, {1, 2}}, @@ -2326,8 +2142,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000094d\U00000308\U0000231a", {2381, 8986}, {2, 3}}, {L"\U0000094d\U00000300", {2381}, {2}}, {L"\U0000094d\U00000308\U00000300", {2381}, {3}}, - {L"\U0000094d\U0000093c", {2381}, {2}}, - {L"\U0000094d\U00000308\U0000093c", {2381}, {3}}, + {L"\U0000094d\U00000900", {2381}, {2}}, + {L"\U0000094d\U00000308\U00000900", {2381}, {3}}, {L"\U0000094d\U0000094d", {2381}, {2}}, {L"\U0000094d\U00000308\U0000094d", {2381}, {3}}, {L"\U0000094d\U0000200d", {2381}, {2}}, @@ -2342,8 +2158,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000200d\U00000308\U0000000a", {8205, 10}, {2, 3}}, {L"\U0000200d\U00000001", {8205, 1}, {1, 2}}, {L"\U0000200d\U00000308\U00000001", {8205, 1}, {2, 3}}, - {L"\U0000200d\U0000034f", {8205}, {2}}, - {L"\U0000200d\U00000308\U0000034f", {8205}, {3}}, + {L"\U0000200d\U0000200c", {8205}, {2}}, + {L"\U0000200d\U00000308\U0000200c", {8205}, {3}}, {L"\U0000200d\U0001f1e6", {8205, 127462}, {1, 3}}, {L"\U0000200d\U00000308\U0001f1e6", {8205, 127462}, {2, 4}}, {L"\U0000200d\U00000600", {8205, 1536}, {1, 2}}, @@ -2360,8 +2176,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000200d\U00000308\U0000ac00", {8205, 44032}, {2, 3}}, {L"\U0000200d\U0000ac01", {8205, 44033}, {1, 2}}, {L"\U0000200d\U00000308\U0000ac01", {8205, 44033}, {2, 3}}, - {L"\U0000200d\U00000900", {8205}, {2}}, - {L"\U0000200d\U00000308\U00000900", {8205}, {3}}, {L"\U0000200d\U00000903", {8205}, {2}}, {L"\U0000200d\U00000308\U00000903", {8205}, {3}}, {L"\U0000200d\U00000904", {8205, 2308}, {1, 2}}, @@ -2374,8 +2188,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000200d\U00000308\U0000231a", {8205, 8986}, {2, 3}}, {L"\U0000200d\U00000300", {8205}, {2}}, {L"\U0000200d\U00000308\U00000300", {8205}, {3}}, - {L"\U0000200d\U0000093c", {8205}, {2}}, - {L"\U0000200d\U00000308\U0000093c", {8205}, {3}}, + {L"\U0000200d\U00000900", {8205}, {2}}, + {L"\U0000200d\U00000308\U00000900", {8205}, {3}}, {L"\U0000200d\U0000094d", {8205}, {2}}, {L"\U0000200d\U00000308\U0000094d", {8205}, {3}}, {L"\U0000200d\U0000200d", {8205}, {2}}, @@ -2390,8 +2204,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000378\U00000308\U0000000a", {888, 10}, {2, 3}}, {L"\U00000378\U00000001", {888, 1}, {1, 2}}, {L"\U00000378\U00000308\U00000001", {888, 1}, {2, 3}}, - {L"\U00000378\U0000034f", {888}, {2}}, - {L"\U00000378\U00000308\U0000034f", {888}, {3}}, + {L"\U00000378\U0000200c", {888}, {2}}, + {L"\U00000378\U00000308\U0000200c", {888}, {3}}, {L"\U00000378\U0001f1e6", {888, 127462}, {1, 3}}, {L"\U00000378\U00000308\U0001f1e6", {888, 127462}, {2, 4}}, {L"\U00000378\U00000600", {888, 1536}, {1, 2}}, @@ -2408,8 +2222,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000378\U00000308\U0000ac00", {888, 44032}, {2, 3}}, {L"\U00000378\U0000ac01", {888, 44033}, {1, 2}}, {L"\U00000378\U00000308\U0000ac01", {888, 44033}, {2, 3}}, - {L"\U00000378\U00000900", {888}, {2}}, - {L"\U00000378\U00000308\U00000900", {888}, {3}}, {L"\U00000378\U00000903", {888}, {2}}, {L"\U00000378\U00000308\U00000903", {888}, {3}}, {L"\U00000378\U00000904", {888, 2308}, {1, 2}}, @@ -2422,8 +2234,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000378\U00000308\U0000231a", {888, 8986}, {2, 3}}, {L"\U00000378\U00000300", {888}, {2}}, {L"\U00000378\U00000308\U00000300", {888}, {3}}, - {L"\U00000378\U0000093c", {888}, {2}}, - {L"\U00000378\U00000308\U0000093c", {888}, {3}}, + {L"\U00000378\U00000900", {888}, {2}}, + {L"\U00000378\U00000308\U00000900", {888}, {3}}, {L"\U00000378\U0000094d", {888}, {2}}, {L"\U00000378\U00000308\U0000094d", {888}, {3}}, {L"\U00000378\U0000200d", {888}, {2}}, @@ -2471,7 +2283,7 @@ std::array, 1187> data_utf16 = {{ /// Note that most of the data for the UTF-16 and UTF-32 are identical. However /// since the size of the code units differ the breaks can contain different /// values. -std::array, 1187> data_utf32 = {{ +std::array, 1093> data_utf32 = {{ {L"\U00000020\U00000020", {32, 32}, {1, 2}}, {L"\U00000020\U00000308\U00000020", {32, 32}, {2, 3}}, {L"\U00000020\U0000000d", {32, 13}, {1, 2}}, @@ -2480,8 +2292,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000020\U00000308\U0000000a", {32, 10}, {2, 3}}, {L"\U00000020\U00000001", {32, 1}, {1, 2}}, {L"\U00000020\U00000308\U00000001", {32, 1}, {2, 3}}, - {L"\U00000020\U0000034f", {32}, {2}}, - {L"\U00000020\U00000308\U0000034f", {32}, {3}}, + {L"\U00000020\U0000200c", {32}, {2}}, + {L"\U00000020\U00000308\U0000200c", {32}, {3}}, {L"\U00000020\U0001f1e6", {32, 127462}, {1, 2}}, {L"\U00000020\U00000308\U0001f1e6", {32, 127462}, {2, 3}}, {L"\U00000020\U00000600", {32, 1536}, {1, 2}}, @@ -2498,8 +2310,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000020\U00000308\U0000ac00", {32, 44032}, {2, 3}}, {L"\U00000020\U0000ac01", {32, 44033}, {1, 2}}, {L"\U00000020\U00000308\U0000ac01", {32, 44033}, {2, 3}}, - {L"\U00000020\U00000900", {32}, {2}}, - {L"\U00000020\U00000308\U00000900", {32}, {3}}, {L"\U00000020\U00000903", {32}, {2}}, {L"\U00000020\U00000308\U00000903", {32}, {3}}, {L"\U00000020\U00000904", {32, 2308}, {1, 2}}, @@ -2512,8 +2322,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000020\U00000308\U0000231a", {32, 8986}, {2, 3}}, {L"\U00000020\U00000300", {32}, {2}}, {L"\U00000020\U00000308\U00000300", {32}, {3}}, - {L"\U00000020\U0000093c", {32}, {2}}, - {L"\U00000020\U00000308\U0000093c", {32}, {3}}, + {L"\U00000020\U00000900", {32}, {2}}, + {L"\U00000020\U00000308\U00000900", {32}, {3}}, {L"\U00000020\U0000094d", {32}, {2}}, {L"\U00000020\U00000308\U0000094d", {32}, {3}}, {L"\U00000020\U0000200d", {32}, {2}}, @@ -2528,8 +2338,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000d\U00000308\U0000000a", {13, 776, 10}, {1, 2, 3}}, {L"\U0000000d\U00000001", {13, 1}, {1, 2}}, {L"\U0000000d\U00000308\U00000001", {13, 776, 1}, {1, 2, 3}}, - {L"\U0000000d\U0000034f", {13, 847}, {1, 2}}, - {L"\U0000000d\U00000308\U0000034f", {13, 776}, {1, 3}}, + {L"\U0000000d\U0000200c", {13, 8204}, {1, 2}}, + {L"\U0000000d\U00000308\U0000200c", {13, 776}, {1, 3}}, {L"\U0000000d\U0001f1e6", {13, 127462}, {1, 2}}, {L"\U0000000d\U00000308\U0001f1e6", {13, 776, 127462}, {1, 2, 3}}, {L"\U0000000d\U00000600", {13, 1536}, {1, 2}}, @@ -2546,8 +2356,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000d\U00000308\U0000ac00", {13, 776, 44032}, {1, 2, 3}}, {L"\U0000000d\U0000ac01", {13, 44033}, {1, 2}}, {L"\U0000000d\U00000308\U0000ac01", {13, 776, 44033}, {1, 2, 3}}, - {L"\U0000000d\U00000900", {13, 2304}, {1, 2}}, - {L"\U0000000d\U00000308\U00000900", {13, 776}, {1, 3}}, {L"\U0000000d\U00000903", {13, 2307}, {1, 2}}, {L"\U0000000d\U00000308\U00000903", {13, 776}, {1, 3}}, {L"\U0000000d\U00000904", {13, 2308}, {1, 2}}, @@ -2560,8 +2368,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000d\U00000308\U0000231a", {13, 776, 8986}, {1, 2, 3}}, {L"\U0000000d\U00000300", {13, 768}, {1, 2}}, {L"\U0000000d\U00000308\U00000300", {13, 776}, {1, 3}}, - {L"\U0000000d\U0000093c", {13, 2364}, {1, 2}}, - {L"\U0000000d\U00000308\U0000093c", {13, 776}, {1, 3}}, + {L"\U0000000d\U00000900", {13, 2304}, {1, 2}}, + {L"\U0000000d\U00000308\U00000900", {13, 776}, {1, 3}}, {L"\U0000000d\U0000094d", {13, 2381}, {1, 2}}, {L"\U0000000d\U00000308\U0000094d", {13, 776}, {1, 3}}, {L"\U0000000d\U0000200d", {13, 8205}, {1, 2}}, @@ -2576,8 +2384,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000a\U00000308\U0000000a", {10, 776, 10}, {1, 2, 3}}, {L"\U0000000a\U00000001", {10, 1}, {1, 2}}, {L"\U0000000a\U00000308\U00000001", {10, 776, 1}, {1, 2, 3}}, - {L"\U0000000a\U0000034f", {10, 847}, {1, 2}}, - {L"\U0000000a\U00000308\U0000034f", {10, 776}, {1, 3}}, + {L"\U0000000a\U0000200c", {10, 8204}, {1, 2}}, + {L"\U0000000a\U00000308\U0000200c", {10, 776}, {1, 3}}, {L"\U0000000a\U0001f1e6", {10, 127462}, {1, 2}}, {L"\U0000000a\U00000308\U0001f1e6", {10, 776, 127462}, {1, 2, 3}}, {L"\U0000000a\U00000600", {10, 1536}, {1, 2}}, @@ -2594,8 +2402,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000a\U00000308\U0000ac00", {10, 776, 44032}, {1, 2, 3}}, {L"\U0000000a\U0000ac01", {10, 44033}, {1, 2}}, {L"\U0000000a\U00000308\U0000ac01", {10, 776, 44033}, {1, 2, 3}}, - {L"\U0000000a\U00000900", {10, 2304}, {1, 2}}, - {L"\U0000000a\U00000308\U00000900", {10, 776}, {1, 3}}, {L"\U0000000a\U00000903", {10, 2307}, {1, 2}}, {L"\U0000000a\U00000308\U00000903", {10, 776}, {1, 3}}, {L"\U0000000a\U00000904", {10, 2308}, {1, 2}}, @@ -2608,8 +2414,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000a\U00000308\U0000231a", {10, 776, 8986}, {1, 2, 3}}, {L"\U0000000a\U00000300", {10, 768}, {1, 2}}, {L"\U0000000a\U00000308\U00000300", {10, 776}, {1, 3}}, - {L"\U0000000a\U0000093c", {10, 2364}, {1, 2}}, - {L"\U0000000a\U00000308\U0000093c", {10, 776}, {1, 3}}, + {L"\U0000000a\U00000900", {10, 2304}, {1, 2}}, + {L"\U0000000a\U00000308\U00000900", {10, 776}, {1, 3}}, {L"\U0000000a\U0000094d", {10, 2381}, {1, 2}}, {L"\U0000000a\U00000308\U0000094d", {10, 776}, {1, 3}}, {L"\U0000000a\U0000200d", {10, 8205}, {1, 2}}, @@ -2624,8 +2430,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000001\U00000308\U0000000a", {1, 776, 10}, {1, 2, 3}}, {L"\U00000001\U00000001", {1, 1}, {1, 2}}, {L"\U00000001\U00000308\U00000001", {1, 776, 1}, {1, 2, 3}}, - {L"\U00000001\U0000034f", {1, 847}, {1, 2}}, - {L"\U00000001\U00000308\U0000034f", {1, 776}, {1, 3}}, + {L"\U00000001\U0000200c", {1, 8204}, {1, 2}}, + {L"\U00000001\U00000308\U0000200c", {1, 776}, {1, 3}}, {L"\U00000001\U0001f1e6", {1, 127462}, {1, 2}}, {L"\U00000001\U00000308\U0001f1e6", {1, 776, 127462}, {1, 2, 3}}, {L"\U00000001\U00000600", {1, 1536}, {1, 2}}, @@ -2642,8 +2448,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000001\U00000308\U0000ac00", {1, 776, 44032}, {1, 2, 3}}, {L"\U00000001\U0000ac01", {1, 44033}, {1, 2}}, {L"\U00000001\U00000308\U0000ac01", {1, 776, 44033}, {1, 2, 3}}, - {L"\U00000001\U00000900", {1, 2304}, {1, 2}}, - {L"\U00000001\U00000308\U00000900", {1, 776}, {1, 3}}, {L"\U00000001\U00000903", {1, 2307}, {1, 2}}, {L"\U00000001\U00000308\U00000903", {1, 776}, {1, 3}}, {L"\U00000001\U00000904", {1, 2308}, {1, 2}}, @@ -2656,62 +2460,60 @@ std::array, 1187> data_utf32 = {{ {L"\U00000001\U00000308\U0000231a", {1, 776, 8986}, {1, 2, 3}}, {L"\U00000001\U00000300", {1, 768}, {1, 2}}, {L"\U00000001\U00000308\U00000300", {1, 776}, {1, 3}}, - {L"\U00000001\U0000093c", {1, 2364}, {1, 2}}, - {L"\U00000001\U00000308\U0000093c", {1, 776}, {1, 3}}, + {L"\U00000001\U00000900", {1, 2304}, {1, 2}}, + {L"\U00000001\U00000308\U00000900", {1, 776}, {1, 3}}, {L"\U00000001\U0000094d", {1, 2381}, {1, 2}}, {L"\U00000001\U00000308\U0000094d", {1, 776}, {1, 3}}, {L"\U00000001\U0000200d", {1, 8205}, {1, 2}}, {L"\U00000001\U00000308\U0000200d", {1, 776}, {1, 3}}, {L"\U00000001\U00000378", {1, 888}, {1, 2}}, {L"\U00000001\U00000308\U00000378", {1, 776, 888}, {1, 2, 3}}, - {L"\U0000034f\U00000020", {847, 32}, {1, 2}}, - {L"\U0000034f\U00000308\U00000020", {847, 32}, {2, 3}}, - {L"\U0000034f\U0000000d", {847, 13}, {1, 2}}, - {L"\U0000034f\U00000308\U0000000d", {847, 13}, {2, 3}}, - {L"\U0000034f\U0000000a", {847, 10}, {1, 2}}, - {L"\U0000034f\U00000308\U0000000a", {847, 10}, {2, 3}}, - {L"\U0000034f\U00000001", {847, 1}, {1, 2}}, - {L"\U0000034f\U00000308\U00000001", {847, 1}, {2, 3}}, - {L"\U0000034f\U0000034f", {847}, {2}}, - {L"\U0000034f\U00000308\U0000034f", {847}, {3}}, - {L"\U0000034f\U0001f1e6", {847, 127462}, {1, 2}}, - {L"\U0000034f\U00000308\U0001f1e6", {847, 127462}, {2, 3}}, - {L"\U0000034f\U00000600", {847, 1536}, {1, 2}}, - {L"\U0000034f\U00000308\U00000600", {847, 1536}, {2, 3}}, - {L"\U0000034f\U00000a03", {847}, {2}}, - {L"\U0000034f\U00000308\U00000a03", {847}, {3}}, - {L"\U0000034f\U00001100", {847, 4352}, {1, 2}}, - {L"\U0000034f\U00000308\U00001100", {847, 4352}, {2, 3}}, - {L"\U0000034f\U00001160", {847, 4448}, {1, 2}}, - {L"\U0000034f\U00000308\U00001160", {847, 4448}, {2, 3}}, - {L"\U0000034f\U000011a8", {847, 4520}, {1, 2}}, - {L"\U0000034f\U00000308\U000011a8", {847, 4520}, {2, 3}}, - {L"\U0000034f\U0000ac00", {847, 44032}, {1, 2}}, - {L"\U0000034f\U00000308\U0000ac00", {847, 44032}, {2, 3}}, - {L"\U0000034f\U0000ac01", {847, 44033}, {1, 2}}, - {L"\U0000034f\U00000308\U0000ac01", {847, 44033}, {2, 3}}, - {L"\U0000034f\U00000900", {847}, {2}}, - {L"\U0000034f\U00000308\U00000900", {847}, {3}}, - {L"\U0000034f\U00000903", {847}, {2}}, - {L"\U0000034f\U00000308\U00000903", {847}, {3}}, - {L"\U0000034f\U00000904", {847, 2308}, {1, 2}}, - {L"\U0000034f\U00000308\U00000904", {847, 2308}, {2, 3}}, - {L"\U0000034f\U00000d4e", {847, 3406}, {1, 2}}, - {L"\U0000034f\U00000308\U00000d4e", {847, 3406}, {2, 3}}, - {L"\U0000034f\U00000915", {847, 2325}, {1, 2}}, - {L"\U0000034f\U00000308\U00000915", {847, 2325}, {2, 3}}, - {L"\U0000034f\U0000231a", {847, 8986}, {1, 2}}, - {L"\U0000034f\U00000308\U0000231a", {847, 8986}, {2, 3}}, - {L"\U0000034f\U00000300", {847}, {2}}, - {L"\U0000034f\U00000308\U00000300", {847}, {3}}, - {L"\U0000034f\U0000093c", {847}, {2}}, - {L"\U0000034f\U00000308\U0000093c", {847}, {3}}, - {L"\U0000034f\U0000094d", {847}, {2}}, - {L"\U0000034f\U00000308\U0000094d", {847}, {3}}, - {L"\U0000034f\U0000200d", {847}, {2}}, - {L"\U0000034f\U00000308\U0000200d", {847}, {3}}, - {L"\U0000034f\U00000378", {847, 888}, {1, 2}}, - {L"\U0000034f\U00000308\U00000378", {847, 888}, {2, 3}}, + {L"\U0000200c\U00000020", {8204, 32}, {1, 2}}, + {L"\U0000200c\U00000308\U00000020", {8204, 32}, {2, 3}}, + {L"\U0000200c\U0000000d", {8204, 13}, {1, 2}}, + {L"\U0000200c\U00000308\U0000000d", {8204, 13}, {2, 3}}, + {L"\U0000200c\U0000000a", {8204, 10}, {1, 2}}, + {L"\U0000200c\U00000308\U0000000a", {8204, 10}, {2, 3}}, + {L"\U0000200c\U00000001", {8204, 1}, {1, 2}}, + {L"\U0000200c\U00000308\U00000001", {8204, 1}, {2, 3}}, + {L"\U0000200c\U0000200c", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000200c", {8204}, {3}}, + {L"\U0000200c\U0001f1e6", {8204, 127462}, {1, 2}}, + {L"\U0000200c\U00000308\U0001f1e6", {8204, 127462}, {2, 3}}, + {L"\U0000200c\U00000600", {8204, 1536}, {1, 2}}, + {L"\U0000200c\U00000308\U00000600", {8204, 1536}, {2, 3}}, + {L"\U0000200c\U00000a03", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000a03", {8204}, {3}}, + {L"\U0000200c\U00001100", {8204, 4352}, {1, 2}}, + {L"\U0000200c\U00000308\U00001100", {8204, 4352}, {2, 3}}, + {L"\U0000200c\U00001160", {8204, 4448}, {1, 2}}, + {L"\U0000200c\U00000308\U00001160", {8204, 4448}, {2, 3}}, + {L"\U0000200c\U000011a8", {8204, 4520}, {1, 2}}, + {L"\U0000200c\U00000308\U000011a8", {8204, 4520}, {2, 3}}, + {L"\U0000200c\U0000ac00", {8204, 44032}, {1, 2}}, + {L"\U0000200c\U00000308\U0000ac00", {8204, 44032}, {2, 3}}, + {L"\U0000200c\U0000ac01", {8204, 44033}, {1, 2}}, + {L"\U0000200c\U00000308\U0000ac01", {8204, 44033}, {2, 3}}, + {L"\U0000200c\U00000903", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000903", {8204}, {3}}, + {L"\U0000200c\U00000904", {8204, 2308}, {1, 2}}, + {L"\U0000200c\U00000308\U00000904", {8204, 2308}, {2, 3}}, + {L"\U0000200c\U00000d4e", {8204, 3406}, {1, 2}}, + {L"\U0000200c\U00000308\U00000d4e", {8204, 3406}, {2, 3}}, + {L"\U0000200c\U00000915", {8204, 2325}, {1, 2}}, + {L"\U0000200c\U00000308\U00000915", {8204, 2325}, {2, 3}}, + {L"\U0000200c\U0000231a", {8204, 8986}, {1, 2}}, + {L"\U0000200c\U00000308\U0000231a", {8204, 8986}, {2, 3}}, + {L"\U0000200c\U00000300", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000300", {8204}, {3}}, + {L"\U0000200c\U00000900", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000900", {8204}, {3}}, + {L"\U0000200c\U0000094d", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000094d", {8204}, {3}}, + {L"\U0000200c\U0000200d", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000200d", {8204}, {3}}, + {L"\U0000200c\U00000378", {8204, 888}, {1, 2}}, + {L"\U0000200c\U00000308\U00000378", {8204, 888}, {2, 3}}, {L"\U0001f1e6\U00000020", {127462, 32}, {1, 2}}, {L"\U0001f1e6\U00000308\U00000020", {127462, 32}, {2, 3}}, {L"\U0001f1e6\U0000000d", {127462, 13}, {1, 2}}, @@ -2720,8 +2522,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0001f1e6\U00000308\U0000000a", {127462, 10}, {2, 3}}, {L"\U0001f1e6\U00000001", {127462, 1}, {1, 2}}, {L"\U0001f1e6\U00000308\U00000001", {127462, 1}, {2, 3}}, - {L"\U0001f1e6\U0000034f", {127462}, {2}}, - {L"\U0001f1e6\U00000308\U0000034f", {127462}, {3}}, + {L"\U0001f1e6\U0000200c", {127462}, {2}}, + {L"\U0001f1e6\U00000308\U0000200c", {127462}, {3}}, {L"\U0001f1e6\U0001f1e6", {127462}, {2}}, {L"\U0001f1e6\U00000308\U0001f1e6", {127462, 127462}, {2, 3}}, {L"\U0001f1e6\U00000600", {127462, 1536}, {1, 2}}, @@ -2738,8 +2540,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0001f1e6\U00000308\U0000ac00", {127462, 44032}, {2, 3}}, {L"\U0001f1e6\U0000ac01", {127462, 44033}, {1, 2}}, {L"\U0001f1e6\U00000308\U0000ac01", {127462, 44033}, {2, 3}}, - {L"\U0001f1e6\U00000900", {127462}, {2}}, - {L"\U0001f1e6\U00000308\U00000900", {127462}, {3}}, {L"\U0001f1e6\U00000903", {127462}, {2}}, {L"\U0001f1e6\U00000308\U00000903", {127462}, {3}}, {L"\U0001f1e6\U00000904", {127462, 2308}, {1, 2}}, @@ -2752,8 +2552,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0001f1e6\U00000308\U0000231a", {127462, 8986}, {2, 3}}, {L"\U0001f1e6\U00000300", {127462}, {2}}, {L"\U0001f1e6\U00000308\U00000300", {127462}, {3}}, - {L"\U0001f1e6\U0000093c", {127462}, {2}}, - {L"\U0001f1e6\U00000308\U0000093c", {127462}, {3}}, + {L"\U0001f1e6\U00000900", {127462}, {2}}, + {L"\U0001f1e6\U00000308\U00000900", {127462}, {3}}, {L"\U0001f1e6\U0000094d", {127462}, {2}}, {L"\U0001f1e6\U00000308\U0000094d", {127462}, {3}}, {L"\U0001f1e6\U0000200d", {127462}, {2}}, @@ -2768,8 +2568,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000600\U00000308\U0000000a", {1536, 10}, {2, 3}}, {L"\U00000600\U00000001", {1536, 1}, {1, 2}}, {L"\U00000600\U00000308\U00000001", {1536, 1}, {2, 3}}, - {L"\U00000600\U0000034f", {1536}, {2}}, - {L"\U00000600\U00000308\U0000034f", {1536}, {3}}, + {L"\U00000600\U0000200c", {1536}, {2}}, + {L"\U00000600\U00000308\U0000200c", {1536}, {3}}, {L"\U00000600\U0001f1e6", {1536}, {2}}, {L"\U00000600\U00000308\U0001f1e6", {1536, 127462}, {2, 3}}, {L"\U00000600\U00000600", {1536}, {2}}, @@ -2786,8 +2586,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000600\U00000308\U0000ac00", {1536, 44032}, {2, 3}}, {L"\U00000600\U0000ac01", {1536}, {2}}, {L"\U00000600\U00000308\U0000ac01", {1536, 44033}, {2, 3}}, - {L"\U00000600\U00000900", {1536}, {2}}, - {L"\U00000600\U00000308\U00000900", {1536}, {3}}, {L"\U00000600\U00000903", {1536}, {2}}, {L"\U00000600\U00000308\U00000903", {1536}, {3}}, {L"\U00000600\U00000904", {1536}, {2}}, @@ -2800,8 +2598,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000600\U00000308\U0000231a", {1536, 8986}, {2, 3}}, {L"\U00000600\U00000300", {1536}, {2}}, {L"\U00000600\U00000308\U00000300", {1536}, {3}}, - {L"\U00000600\U0000093c", {1536}, {2}}, - {L"\U00000600\U00000308\U0000093c", {1536}, {3}}, + {L"\U00000600\U00000900", {1536}, {2}}, + {L"\U00000600\U00000308\U00000900", {1536}, {3}}, {L"\U00000600\U0000094d", {1536}, {2}}, {L"\U00000600\U00000308\U0000094d", {1536}, {3}}, {L"\U00000600\U0000200d", {1536}, {2}}, @@ -2816,8 +2614,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000a03\U00000308\U0000000a", {2563, 10}, {2, 3}}, {L"\U00000a03\U00000001", {2563, 1}, {1, 2}}, {L"\U00000a03\U00000308\U00000001", {2563, 1}, {2, 3}}, - {L"\U00000a03\U0000034f", {2563}, {2}}, - {L"\U00000a03\U00000308\U0000034f", {2563}, {3}}, + {L"\U00000a03\U0000200c", {2563}, {2}}, + {L"\U00000a03\U00000308\U0000200c", {2563}, {3}}, {L"\U00000a03\U0001f1e6", {2563, 127462}, {1, 2}}, {L"\U00000a03\U00000308\U0001f1e6", {2563, 127462}, {2, 3}}, {L"\U00000a03\U00000600", {2563, 1536}, {1, 2}}, @@ -2834,8 +2632,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000a03\U00000308\U0000ac00", {2563, 44032}, {2, 3}}, {L"\U00000a03\U0000ac01", {2563, 44033}, {1, 2}}, {L"\U00000a03\U00000308\U0000ac01", {2563, 44033}, {2, 3}}, - {L"\U00000a03\U00000900", {2563}, {2}}, - {L"\U00000a03\U00000308\U00000900", {2563}, {3}}, {L"\U00000a03\U00000903", {2563}, {2}}, {L"\U00000a03\U00000308\U00000903", {2563}, {3}}, {L"\U00000a03\U00000904", {2563, 2308}, {1, 2}}, @@ -2848,8 +2644,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000a03\U00000308\U0000231a", {2563, 8986}, {2, 3}}, {L"\U00000a03\U00000300", {2563}, {2}}, {L"\U00000a03\U00000308\U00000300", {2563}, {3}}, - {L"\U00000a03\U0000093c", {2563}, {2}}, - {L"\U00000a03\U00000308\U0000093c", {2563}, {3}}, + {L"\U00000a03\U00000900", {2563}, {2}}, + {L"\U00000a03\U00000308\U00000900", {2563}, {3}}, {L"\U00000a03\U0000094d", {2563}, {2}}, {L"\U00000a03\U00000308\U0000094d", {2563}, {3}}, {L"\U00000a03\U0000200d", {2563}, {2}}, @@ -2864,8 +2660,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00001100\U00000308\U0000000a", {4352, 10}, {2, 3}}, {L"\U00001100\U00000001", {4352, 1}, {1, 2}}, {L"\U00001100\U00000308\U00000001", {4352, 1}, {2, 3}}, - {L"\U00001100\U0000034f", {4352}, {2}}, - {L"\U00001100\U00000308\U0000034f", {4352}, {3}}, + {L"\U00001100\U0000200c", {4352}, {2}}, + {L"\U00001100\U00000308\U0000200c", {4352}, {3}}, {L"\U00001100\U0001f1e6", {4352, 127462}, {1, 2}}, {L"\U00001100\U00000308\U0001f1e6", {4352, 127462}, {2, 3}}, {L"\U00001100\U00000600", {4352, 1536}, {1, 2}}, @@ -2882,8 +2678,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00001100\U00000308\U0000ac00", {4352, 44032}, {2, 3}}, {L"\U00001100\U0000ac01", {4352}, {2}}, {L"\U00001100\U00000308\U0000ac01", {4352, 44033}, {2, 3}}, - {L"\U00001100\U00000900", {4352}, {2}}, - {L"\U00001100\U00000308\U00000900", {4352}, {3}}, {L"\U00001100\U00000903", {4352}, {2}}, {L"\U00001100\U00000308\U00000903", {4352}, {3}}, {L"\U00001100\U00000904", {4352, 2308}, {1, 2}}, @@ -2896,8 +2690,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00001100\U00000308\U0000231a", {4352, 8986}, {2, 3}}, {L"\U00001100\U00000300", {4352}, {2}}, {L"\U00001100\U00000308\U00000300", {4352}, {3}}, - {L"\U00001100\U0000093c", {4352}, {2}}, - {L"\U00001100\U00000308\U0000093c", {4352}, {3}}, + {L"\U00001100\U00000900", {4352}, {2}}, + {L"\U00001100\U00000308\U00000900", {4352}, {3}}, {L"\U00001100\U0000094d", {4352}, {2}}, {L"\U00001100\U00000308\U0000094d", {4352}, {3}}, {L"\U00001100\U0000200d", {4352}, {2}}, @@ -2912,8 +2706,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00001160\U00000308\U0000000a", {4448, 10}, {2, 3}}, {L"\U00001160\U00000001", {4448, 1}, {1, 2}}, {L"\U00001160\U00000308\U00000001", {4448, 1}, {2, 3}}, - {L"\U00001160\U0000034f", {4448}, {2}}, - {L"\U00001160\U00000308\U0000034f", {4448}, {3}}, + {L"\U00001160\U0000200c", {4448}, {2}}, + {L"\U00001160\U00000308\U0000200c", {4448}, {3}}, {L"\U00001160\U0001f1e6", {4448, 127462}, {1, 2}}, {L"\U00001160\U00000308\U0001f1e6", {4448, 127462}, {2, 3}}, {L"\U00001160\U00000600", {4448, 1536}, {1, 2}}, @@ -2930,8 +2724,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00001160\U00000308\U0000ac00", {4448, 44032}, {2, 3}}, {L"\U00001160\U0000ac01", {4448, 44033}, {1, 2}}, {L"\U00001160\U00000308\U0000ac01", {4448, 44033}, {2, 3}}, - {L"\U00001160\U00000900", {4448}, {2}}, - {L"\U00001160\U00000308\U00000900", {4448}, {3}}, {L"\U00001160\U00000903", {4448}, {2}}, {L"\U00001160\U00000308\U00000903", {4448}, {3}}, {L"\U00001160\U00000904", {4448, 2308}, {1, 2}}, @@ -2944,8 +2736,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00001160\U00000308\U0000231a", {4448, 8986}, {2, 3}}, {L"\U00001160\U00000300", {4448}, {2}}, {L"\U00001160\U00000308\U00000300", {4448}, {3}}, - {L"\U00001160\U0000093c", {4448}, {2}}, - {L"\U00001160\U00000308\U0000093c", {4448}, {3}}, + {L"\U00001160\U00000900", {4448}, {2}}, + {L"\U00001160\U00000308\U00000900", {4448}, {3}}, {L"\U00001160\U0000094d", {4448}, {2}}, {L"\U00001160\U00000308\U0000094d", {4448}, {3}}, {L"\U00001160\U0000200d", {4448}, {2}}, @@ -2960,8 +2752,8 @@ std::array, 1187> data_utf32 = {{ {L"\U000011a8\U00000308\U0000000a", {4520, 10}, {2, 3}}, {L"\U000011a8\U00000001", {4520, 1}, {1, 2}}, {L"\U000011a8\U00000308\U00000001", {4520, 1}, {2, 3}}, - {L"\U000011a8\U0000034f", {4520}, {2}}, - {L"\U000011a8\U00000308\U0000034f", {4520}, {3}}, + {L"\U000011a8\U0000200c", {4520}, {2}}, + {L"\U000011a8\U00000308\U0000200c", {4520}, {3}}, {L"\U000011a8\U0001f1e6", {4520, 127462}, {1, 2}}, {L"\U000011a8\U00000308\U0001f1e6", {4520, 127462}, {2, 3}}, {L"\U000011a8\U00000600", {4520, 1536}, {1, 2}}, @@ -2978,8 +2770,6 @@ std::array, 1187> data_utf32 = {{ {L"\U000011a8\U00000308\U0000ac00", {4520, 44032}, {2, 3}}, {L"\U000011a8\U0000ac01", {4520, 44033}, {1, 2}}, {L"\U000011a8\U00000308\U0000ac01", {4520, 44033}, {2, 3}}, - {L"\U000011a8\U00000900", {4520}, {2}}, - {L"\U000011a8\U00000308\U00000900", {4520}, {3}}, {L"\U000011a8\U00000903", {4520}, {2}}, {L"\U000011a8\U00000308\U00000903", {4520}, {3}}, {L"\U000011a8\U00000904", {4520, 2308}, {1, 2}}, @@ -2992,8 +2782,8 @@ std::array, 1187> data_utf32 = {{ {L"\U000011a8\U00000308\U0000231a", {4520, 8986}, {2, 3}}, {L"\U000011a8\U00000300", {4520}, {2}}, {L"\U000011a8\U00000308\U00000300", {4520}, {3}}, - {L"\U000011a8\U0000093c", {4520}, {2}}, - {L"\U000011a8\U00000308\U0000093c", {4520}, {3}}, + {L"\U000011a8\U00000900", {4520}, {2}}, + {L"\U000011a8\U00000308\U00000900", {4520}, {3}}, {L"\U000011a8\U0000094d", {4520}, {2}}, {L"\U000011a8\U00000308\U0000094d", {4520}, {3}}, {L"\U000011a8\U0000200d", {4520}, {2}}, @@ -3008,8 +2798,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac00\U00000308\U0000000a", {44032, 10}, {2, 3}}, {L"\U0000ac00\U00000001", {44032, 1}, {1, 2}}, {L"\U0000ac00\U00000308\U00000001", {44032, 1}, {2, 3}}, - {L"\U0000ac00\U0000034f", {44032}, {2}}, - {L"\U0000ac00\U00000308\U0000034f", {44032}, {3}}, + {L"\U0000ac00\U0000200c", {44032}, {2}}, + {L"\U0000ac00\U00000308\U0000200c", {44032}, {3}}, {L"\U0000ac00\U0001f1e6", {44032, 127462}, {1, 2}}, {L"\U0000ac00\U00000308\U0001f1e6", {44032, 127462}, {2, 3}}, {L"\U0000ac00\U00000600", {44032, 1536}, {1, 2}}, @@ -3026,8 +2816,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac00\U00000308\U0000ac00", {44032, 44032}, {2, 3}}, {L"\U0000ac00\U0000ac01", {44032, 44033}, {1, 2}}, {L"\U0000ac00\U00000308\U0000ac01", {44032, 44033}, {2, 3}}, - {L"\U0000ac00\U00000900", {44032}, {2}}, - {L"\U0000ac00\U00000308\U00000900", {44032}, {3}}, {L"\U0000ac00\U00000903", {44032}, {2}}, {L"\U0000ac00\U00000308\U00000903", {44032}, {3}}, {L"\U0000ac00\U00000904", {44032, 2308}, {1, 2}}, @@ -3040,8 +2828,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac00\U00000308\U0000231a", {44032, 8986}, {2, 3}}, {L"\U0000ac00\U00000300", {44032}, {2}}, {L"\U0000ac00\U00000308\U00000300", {44032}, {3}}, - {L"\U0000ac00\U0000093c", {44032}, {2}}, - {L"\U0000ac00\U00000308\U0000093c", {44032}, {3}}, + {L"\U0000ac00\U00000900", {44032}, {2}}, + {L"\U0000ac00\U00000308\U00000900", {44032}, {3}}, {L"\U0000ac00\U0000094d", {44032}, {2}}, {L"\U0000ac00\U00000308\U0000094d", {44032}, {3}}, {L"\U0000ac00\U0000200d", {44032}, {2}}, @@ -3056,8 +2844,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac01\U00000308\U0000000a", {44033, 10}, {2, 3}}, {L"\U0000ac01\U00000001", {44033, 1}, {1, 2}}, {L"\U0000ac01\U00000308\U00000001", {44033, 1}, {2, 3}}, - {L"\U0000ac01\U0000034f", {44033}, {2}}, - {L"\U0000ac01\U00000308\U0000034f", {44033}, {3}}, + {L"\U0000ac01\U0000200c", {44033}, {2}}, + {L"\U0000ac01\U00000308\U0000200c", {44033}, {3}}, {L"\U0000ac01\U0001f1e6", {44033, 127462}, {1, 2}}, {L"\U0000ac01\U00000308\U0001f1e6", {44033, 127462}, {2, 3}}, {L"\U0000ac01\U00000600", {44033, 1536}, {1, 2}}, @@ -3074,8 +2862,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac01\U00000308\U0000ac00", {44033, 44032}, {2, 3}}, {L"\U0000ac01\U0000ac01", {44033, 44033}, {1, 2}}, {L"\U0000ac01\U00000308\U0000ac01", {44033, 44033}, {2, 3}}, - {L"\U0000ac01\U00000900", {44033}, {2}}, - {L"\U0000ac01\U00000308\U00000900", {44033}, {3}}, {L"\U0000ac01\U00000903", {44033}, {2}}, {L"\U0000ac01\U00000308\U00000903", {44033}, {3}}, {L"\U0000ac01\U00000904", {44033, 2308}, {1, 2}}, @@ -3088,62 +2874,14 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac01\U00000308\U0000231a", {44033, 8986}, {2, 3}}, {L"\U0000ac01\U00000300", {44033}, {2}}, {L"\U0000ac01\U00000308\U00000300", {44033}, {3}}, - {L"\U0000ac01\U0000093c", {44033}, {2}}, - {L"\U0000ac01\U00000308\U0000093c", {44033}, {3}}, + {L"\U0000ac01\U00000900", {44033}, {2}}, + {L"\U0000ac01\U00000308\U00000900", {44033}, {3}}, {L"\U0000ac01\U0000094d", {44033}, {2}}, {L"\U0000ac01\U00000308\U0000094d", {44033}, {3}}, {L"\U0000ac01\U0000200d", {44033}, {2}}, {L"\U0000ac01\U00000308\U0000200d", {44033}, {3}}, {L"\U0000ac01\U00000378", {44033, 888}, {1, 2}}, {L"\U0000ac01\U00000308\U00000378", {44033, 888}, {2, 3}}, - {L"\U00000900\U00000020", {2304, 32}, {1, 2}}, - {L"\U00000900\U00000308\U00000020", {2304, 32}, {2, 3}}, - {L"\U00000900\U0000000d", {2304, 13}, {1, 2}}, - {L"\U00000900\U00000308\U0000000d", {2304, 13}, {2, 3}}, - {L"\U00000900\U0000000a", {2304, 10}, {1, 2}}, - {L"\U00000900\U00000308\U0000000a", {2304, 10}, {2, 3}}, - {L"\U00000900\U00000001", {2304, 1}, {1, 2}}, - {L"\U00000900\U00000308\U00000001", {2304, 1}, {2, 3}}, - {L"\U00000900\U0000034f", {2304}, {2}}, - {L"\U00000900\U00000308\U0000034f", {2304}, {3}}, - {L"\U00000900\U0001f1e6", {2304, 127462}, {1, 2}}, - {L"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {2, 3}}, - {L"\U00000900\U00000600", {2304, 1536}, {1, 2}}, - {L"\U00000900\U00000308\U00000600", {2304, 1536}, {2, 3}}, - {L"\U00000900\U00000a03", {2304}, {2}}, - {L"\U00000900\U00000308\U00000a03", {2304}, {3}}, - {L"\U00000900\U00001100", {2304, 4352}, {1, 2}}, - {L"\U00000900\U00000308\U00001100", {2304, 4352}, {2, 3}}, - {L"\U00000900\U00001160", {2304, 4448}, {1, 2}}, - {L"\U00000900\U00000308\U00001160", {2304, 4448}, {2, 3}}, - {L"\U00000900\U000011a8", {2304, 4520}, {1, 2}}, - {L"\U00000900\U00000308\U000011a8", {2304, 4520}, {2, 3}}, - {L"\U00000900\U0000ac00", {2304, 44032}, {1, 2}}, - {L"\U00000900\U00000308\U0000ac00", {2304, 44032}, {2, 3}}, - {L"\U00000900\U0000ac01", {2304, 44033}, {1, 2}}, - {L"\U00000900\U00000308\U0000ac01", {2304, 44033}, {2, 3}}, - {L"\U00000900\U00000900", {2304}, {2}}, - {L"\U00000900\U00000308\U00000900", {2304}, {3}}, - {L"\U00000900\U00000903", {2304}, {2}}, - {L"\U00000900\U00000308\U00000903", {2304}, {3}}, - {L"\U00000900\U00000904", {2304, 2308}, {1, 2}}, - {L"\U00000900\U00000308\U00000904", {2304, 2308}, {2, 3}}, - {L"\U00000900\U00000d4e", {2304, 3406}, {1, 2}}, - {L"\U00000900\U00000308\U00000d4e", {2304, 3406}, {2, 3}}, - {L"\U00000900\U00000915", {2304, 2325}, {1, 2}}, - {L"\U00000900\U00000308\U00000915", {2304, 2325}, {2, 3}}, - {L"\U00000900\U0000231a", {2304, 8986}, {1, 2}}, - {L"\U00000900\U00000308\U0000231a", {2304, 8986}, {2, 3}}, - {L"\U00000900\U00000300", {2304}, {2}}, - {L"\U00000900\U00000308\U00000300", {2304}, {3}}, - {L"\U00000900\U0000093c", {2304}, {2}}, - {L"\U00000900\U00000308\U0000093c", {2304}, {3}}, - {L"\U00000900\U0000094d", {2304}, {2}}, - {L"\U00000900\U00000308\U0000094d", {2304}, {3}}, - {L"\U00000900\U0000200d", {2304}, {2}}, - {L"\U00000900\U00000308\U0000200d", {2304}, {3}}, - {L"\U00000900\U00000378", {2304, 888}, {1, 2}}, - {L"\U00000900\U00000308\U00000378", {2304, 888}, {2, 3}}, {L"\U00000903\U00000020", {2307, 32}, {1, 2}}, {L"\U00000903\U00000308\U00000020", {2307, 32}, {2, 3}}, {L"\U00000903\U0000000d", {2307, 13}, {1, 2}}, @@ -3152,8 +2890,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000903\U00000308\U0000000a", {2307, 10}, {2, 3}}, {L"\U00000903\U00000001", {2307, 1}, {1, 2}}, {L"\U00000903\U00000308\U00000001", {2307, 1}, {2, 3}}, - {L"\U00000903\U0000034f", {2307}, {2}}, - {L"\U00000903\U00000308\U0000034f", {2307}, {3}}, + {L"\U00000903\U0000200c", {2307}, {2}}, + {L"\U00000903\U00000308\U0000200c", {2307}, {3}}, {L"\U00000903\U0001f1e6", {2307, 127462}, {1, 2}}, {L"\U00000903\U00000308\U0001f1e6", {2307, 127462}, {2, 3}}, {L"\U00000903\U00000600", {2307, 1536}, {1, 2}}, @@ -3170,8 +2908,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000903\U00000308\U0000ac00", {2307, 44032}, {2, 3}}, {L"\U00000903\U0000ac01", {2307, 44033}, {1, 2}}, {L"\U00000903\U00000308\U0000ac01", {2307, 44033}, {2, 3}}, - {L"\U00000903\U00000900", {2307}, {2}}, - {L"\U00000903\U00000308\U00000900", {2307}, {3}}, {L"\U00000903\U00000903", {2307}, {2}}, {L"\U00000903\U00000308\U00000903", {2307}, {3}}, {L"\U00000903\U00000904", {2307, 2308}, {1, 2}}, @@ -3184,8 +2920,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000903\U00000308\U0000231a", {2307, 8986}, {2, 3}}, {L"\U00000903\U00000300", {2307}, {2}}, {L"\U00000903\U00000308\U00000300", {2307}, {3}}, - {L"\U00000903\U0000093c", {2307}, {2}}, - {L"\U00000903\U00000308\U0000093c", {2307}, {3}}, + {L"\U00000903\U00000900", {2307}, {2}}, + {L"\U00000903\U00000308\U00000900", {2307}, {3}}, {L"\U00000903\U0000094d", {2307}, {2}}, {L"\U00000903\U00000308\U0000094d", {2307}, {3}}, {L"\U00000903\U0000200d", {2307}, {2}}, @@ -3200,8 +2936,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000904\U00000308\U0000000a", {2308, 10}, {2, 3}}, {L"\U00000904\U00000001", {2308, 1}, {1, 2}}, {L"\U00000904\U00000308\U00000001", {2308, 1}, {2, 3}}, - {L"\U00000904\U0000034f", {2308}, {2}}, - {L"\U00000904\U00000308\U0000034f", {2308}, {3}}, + {L"\U00000904\U0000200c", {2308}, {2}}, + {L"\U00000904\U00000308\U0000200c", {2308}, {3}}, {L"\U00000904\U0001f1e6", {2308, 127462}, {1, 2}}, {L"\U00000904\U00000308\U0001f1e6", {2308, 127462}, {2, 3}}, {L"\U00000904\U00000600", {2308, 1536}, {1, 2}}, @@ -3218,8 +2954,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000904\U00000308\U0000ac00", {2308, 44032}, {2, 3}}, {L"\U00000904\U0000ac01", {2308, 44033}, {1, 2}}, {L"\U00000904\U00000308\U0000ac01", {2308, 44033}, {2, 3}}, - {L"\U00000904\U00000900", {2308}, {2}}, - {L"\U00000904\U00000308\U00000900", {2308}, {3}}, {L"\U00000904\U00000903", {2308}, {2}}, {L"\U00000904\U00000308\U00000903", {2308}, {3}}, {L"\U00000904\U00000904", {2308, 2308}, {1, 2}}, @@ -3232,8 +2966,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000904\U00000308\U0000231a", {2308, 8986}, {2, 3}}, {L"\U00000904\U00000300", {2308}, {2}}, {L"\U00000904\U00000308\U00000300", {2308}, {3}}, - {L"\U00000904\U0000093c", {2308}, {2}}, - {L"\U00000904\U00000308\U0000093c", {2308}, {3}}, + {L"\U00000904\U00000900", {2308}, {2}}, + {L"\U00000904\U00000308\U00000900", {2308}, {3}}, {L"\U00000904\U0000094d", {2308}, {2}}, {L"\U00000904\U00000308\U0000094d", {2308}, {3}}, {L"\U00000904\U0000200d", {2308}, {2}}, @@ -3248,8 +2982,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000d4e\U00000308\U0000000a", {3406, 10}, {2, 3}}, {L"\U00000d4e\U00000001", {3406, 1}, {1, 2}}, {L"\U00000d4e\U00000308\U00000001", {3406, 1}, {2, 3}}, - {L"\U00000d4e\U0000034f", {3406}, {2}}, - {L"\U00000d4e\U00000308\U0000034f", {3406}, {3}}, + {L"\U00000d4e\U0000200c", {3406}, {2}}, + {L"\U00000d4e\U00000308\U0000200c", {3406}, {3}}, {L"\U00000d4e\U0001f1e6", {3406}, {2}}, {L"\U00000d4e\U00000308\U0001f1e6", {3406, 127462}, {2, 3}}, {L"\U00000d4e\U00000600", {3406}, {2}}, @@ -3266,8 +3000,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000d4e\U00000308\U0000ac00", {3406, 44032}, {2, 3}}, {L"\U00000d4e\U0000ac01", {3406}, {2}}, {L"\U00000d4e\U00000308\U0000ac01", {3406, 44033}, {2, 3}}, - {L"\U00000d4e\U00000900", {3406}, {2}}, - {L"\U00000d4e\U00000308\U00000900", {3406}, {3}}, {L"\U00000d4e\U00000903", {3406}, {2}}, {L"\U00000d4e\U00000308\U00000903", {3406}, {3}}, {L"\U00000d4e\U00000904", {3406}, {2}}, @@ -3280,8 +3012,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000d4e\U00000308\U0000231a", {3406, 8986}, {2, 3}}, {L"\U00000d4e\U00000300", {3406}, {2}}, {L"\U00000d4e\U00000308\U00000300", {3406}, {3}}, - {L"\U00000d4e\U0000093c", {3406}, {2}}, - {L"\U00000d4e\U00000308\U0000093c", {3406}, {3}}, + {L"\U00000d4e\U00000900", {3406}, {2}}, + {L"\U00000d4e\U00000308\U00000900", {3406}, {3}}, {L"\U00000d4e\U0000094d", {3406}, {2}}, {L"\U00000d4e\U00000308\U0000094d", {3406}, {3}}, {L"\U00000d4e\U0000200d", {3406}, {2}}, @@ -3296,8 +3028,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000915\U00000308\U0000000a", {2325, 10}, {2, 3}}, {L"\U00000915\U00000001", {2325, 1}, {1, 2}}, {L"\U00000915\U00000308\U00000001", {2325, 1}, {2, 3}}, - {L"\U00000915\U0000034f", {2325}, {2}}, - {L"\U00000915\U00000308\U0000034f", {2325}, {3}}, + {L"\U00000915\U0000200c", {2325}, {2}}, + {L"\U00000915\U00000308\U0000200c", {2325}, {3}}, {L"\U00000915\U0001f1e6", {2325, 127462}, {1, 2}}, {L"\U00000915\U00000308\U0001f1e6", {2325, 127462}, {2, 3}}, {L"\U00000915\U00000600", {2325, 1536}, {1, 2}}, @@ -3314,8 +3046,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000915\U00000308\U0000ac00", {2325, 44032}, {2, 3}}, {L"\U00000915\U0000ac01", {2325, 44033}, {1, 2}}, {L"\U00000915\U00000308\U0000ac01", {2325, 44033}, {2, 3}}, - {L"\U00000915\U00000900", {2325}, {2}}, - {L"\U00000915\U00000308\U00000900", {2325}, {3}}, {L"\U00000915\U00000903", {2325}, {2}}, {L"\U00000915\U00000308\U00000903", {2325}, {3}}, {L"\U00000915\U00000904", {2325, 2308}, {1, 2}}, @@ -3328,8 +3058,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000915\U00000308\U0000231a", {2325, 8986}, {2, 3}}, {L"\U00000915\U00000300", {2325}, {2}}, {L"\U00000915\U00000308\U00000300", {2325}, {3}}, - {L"\U00000915\U0000093c", {2325}, {2}}, - {L"\U00000915\U00000308\U0000093c", {2325}, {3}}, + {L"\U00000915\U00000900", {2325}, {2}}, + {L"\U00000915\U00000308\U00000900", {2325}, {3}}, {L"\U00000915\U0000094d", {2325}, {2}}, {L"\U00000915\U00000308\U0000094d", {2325}, {3}}, {L"\U00000915\U0000200d", {2325}, {2}}, @@ -3344,8 +3074,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000231a\U00000308\U0000000a", {8986, 10}, {2, 3}}, {L"\U0000231a\U00000001", {8986, 1}, {1, 2}}, {L"\U0000231a\U00000308\U00000001", {8986, 1}, {2, 3}}, - {L"\U0000231a\U0000034f", {8986}, {2}}, - {L"\U0000231a\U00000308\U0000034f", {8986}, {3}}, + {L"\U0000231a\U0000200c", {8986}, {2}}, + {L"\U0000231a\U00000308\U0000200c", {8986}, {3}}, {L"\U0000231a\U0001f1e6", {8986, 127462}, {1, 2}}, {L"\U0000231a\U00000308\U0001f1e6", {8986, 127462}, {2, 3}}, {L"\U0000231a\U00000600", {8986, 1536}, {1, 2}}, @@ -3362,8 +3092,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000231a\U00000308\U0000ac00", {8986, 44032}, {2, 3}}, {L"\U0000231a\U0000ac01", {8986, 44033}, {1, 2}}, {L"\U0000231a\U00000308\U0000ac01", {8986, 44033}, {2, 3}}, - {L"\U0000231a\U00000900", {8986}, {2}}, - {L"\U0000231a\U00000308\U00000900", {8986}, {3}}, {L"\U0000231a\U00000903", {8986}, {2}}, {L"\U0000231a\U00000308\U00000903", {8986}, {3}}, {L"\U0000231a\U00000904", {8986, 2308}, {1, 2}}, @@ -3376,8 +3104,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000231a\U00000308\U0000231a", {8986, 8986}, {2, 3}}, {L"\U0000231a\U00000300", {8986}, {2}}, {L"\U0000231a\U00000308\U00000300", {8986}, {3}}, - {L"\U0000231a\U0000093c", {8986}, {2}}, - {L"\U0000231a\U00000308\U0000093c", {8986}, {3}}, + {L"\U0000231a\U00000900", {8986}, {2}}, + {L"\U0000231a\U00000308\U00000900", {8986}, {3}}, {L"\U0000231a\U0000094d", {8986}, {2}}, {L"\U0000231a\U00000308\U0000094d", {8986}, {3}}, {L"\U0000231a\U0000200d", {8986}, {2}}, @@ -3392,8 +3120,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000300\U00000308\U0000000a", {768, 10}, {2, 3}}, {L"\U00000300\U00000001", {768, 1}, {1, 2}}, {L"\U00000300\U00000308\U00000001", {768, 1}, {2, 3}}, - {L"\U00000300\U0000034f", {768}, {2}}, - {L"\U00000300\U00000308\U0000034f", {768}, {3}}, + {L"\U00000300\U0000200c", {768}, {2}}, + {L"\U00000300\U00000308\U0000200c", {768}, {3}}, {L"\U00000300\U0001f1e6", {768, 127462}, {1, 2}}, {L"\U00000300\U00000308\U0001f1e6", {768, 127462}, {2, 3}}, {L"\U00000300\U00000600", {768, 1536}, {1, 2}}, @@ -3410,8 +3138,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000300\U00000308\U0000ac00", {768, 44032}, {2, 3}}, {L"\U00000300\U0000ac01", {768, 44033}, {1, 2}}, {L"\U00000300\U00000308\U0000ac01", {768, 44033}, {2, 3}}, - {L"\U00000300\U00000900", {768}, {2}}, - {L"\U00000300\U00000308\U00000900", {768}, {3}}, {L"\U00000300\U00000903", {768}, {2}}, {L"\U00000300\U00000308\U00000903", {768}, {3}}, {L"\U00000300\U00000904", {768, 2308}, {1, 2}}, @@ -3424,62 +3150,60 @@ std::array, 1187> data_utf32 = {{ {L"\U00000300\U00000308\U0000231a", {768, 8986}, {2, 3}}, {L"\U00000300\U00000300", {768}, {2}}, {L"\U00000300\U00000308\U00000300", {768}, {3}}, - {L"\U00000300\U0000093c", {768}, {2}}, - {L"\U00000300\U00000308\U0000093c", {768}, {3}}, + {L"\U00000300\U00000900", {768}, {2}}, + {L"\U00000300\U00000308\U00000900", {768}, {3}}, {L"\U00000300\U0000094d", {768}, {2}}, {L"\U00000300\U00000308\U0000094d", {768}, {3}}, {L"\U00000300\U0000200d", {768}, {2}}, {L"\U00000300\U00000308\U0000200d", {768}, {3}}, {L"\U00000300\U00000378", {768, 888}, {1, 2}}, {L"\U00000300\U00000308\U00000378", {768, 888}, {2, 3}}, - {L"\U0000093c\U00000020", {2364, 32}, {1, 2}}, - {L"\U0000093c\U00000308\U00000020", {2364, 32}, {2, 3}}, - {L"\U0000093c\U0000000d", {2364, 13}, {1, 2}}, - {L"\U0000093c\U00000308\U0000000d", {2364, 13}, {2, 3}}, - {L"\U0000093c\U0000000a", {2364, 10}, {1, 2}}, - {L"\U0000093c\U00000308\U0000000a", {2364, 10}, {2, 3}}, - {L"\U0000093c\U00000001", {2364, 1}, {1, 2}}, - {L"\U0000093c\U00000308\U00000001", {2364, 1}, {2, 3}}, - {L"\U0000093c\U0000034f", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000034f", {2364}, {3}}, - {L"\U0000093c\U0001f1e6", {2364, 127462}, {1, 2}}, - {L"\U0000093c\U00000308\U0001f1e6", {2364, 127462}, {2, 3}}, - {L"\U0000093c\U00000600", {2364, 1536}, {1, 2}}, - {L"\U0000093c\U00000308\U00000600", {2364, 1536}, {2, 3}}, - {L"\U0000093c\U00000a03", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000a03", {2364}, {3}}, - {L"\U0000093c\U00001100", {2364, 4352}, {1, 2}}, - {L"\U0000093c\U00000308\U00001100", {2364, 4352}, {2, 3}}, - {L"\U0000093c\U00001160", {2364, 4448}, {1, 2}}, - {L"\U0000093c\U00000308\U00001160", {2364, 4448}, {2, 3}}, - {L"\U0000093c\U000011a8", {2364, 4520}, {1, 2}}, - {L"\U0000093c\U00000308\U000011a8", {2364, 4520}, {2, 3}}, - {L"\U0000093c\U0000ac00", {2364, 44032}, {1, 2}}, - {L"\U0000093c\U00000308\U0000ac00", {2364, 44032}, {2, 3}}, - {L"\U0000093c\U0000ac01", {2364, 44033}, {1, 2}}, - {L"\U0000093c\U00000308\U0000ac01", {2364, 44033}, {2, 3}}, - {L"\U0000093c\U00000900", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000900", {2364}, {3}}, - {L"\U0000093c\U00000903", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000903", {2364}, {3}}, - {L"\U0000093c\U00000904", {2364, 2308}, {1, 2}}, - {L"\U0000093c\U00000308\U00000904", {2364, 2308}, {2, 3}}, - {L"\U0000093c\U00000d4e", {2364, 3406}, {1, 2}}, - {L"\U0000093c\U00000308\U00000d4e", {2364, 3406}, {2, 3}}, - {L"\U0000093c\U00000915", {2364, 2325}, {1, 2}}, - {L"\U0000093c\U00000308\U00000915", {2364, 2325}, {2, 3}}, - {L"\U0000093c\U0000231a", {2364, 8986}, {1, 2}}, - {L"\U0000093c\U00000308\U0000231a", {2364, 8986}, {2, 3}}, - {L"\U0000093c\U00000300", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000300", {2364}, {3}}, - {L"\U0000093c\U0000093c", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000093c", {2364}, {3}}, - {L"\U0000093c\U0000094d", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000094d", {2364}, {3}}, - {L"\U0000093c\U0000200d", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000200d", {2364}, {3}}, - {L"\U0000093c\U00000378", {2364, 888}, {1, 2}}, - {L"\U0000093c\U00000308\U00000378", {2364, 888}, {2, 3}}, + {L"\U00000900\U00000020", {2304, 32}, {1, 2}}, + {L"\U00000900\U00000308\U00000020", {2304, 32}, {2, 3}}, + {L"\U00000900\U0000000d", {2304, 13}, {1, 2}}, + {L"\U00000900\U00000308\U0000000d", {2304, 13}, {2, 3}}, + {L"\U00000900\U0000000a", {2304, 10}, {1, 2}}, + {L"\U00000900\U00000308\U0000000a", {2304, 10}, {2, 3}}, + {L"\U00000900\U00000001", {2304, 1}, {1, 2}}, + {L"\U00000900\U00000308\U00000001", {2304, 1}, {2, 3}}, + {L"\U00000900\U0000200c", {2304}, {2}}, + {L"\U00000900\U00000308\U0000200c", {2304}, {3}}, + {L"\U00000900\U0001f1e6", {2304, 127462}, {1, 2}}, + {L"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {2, 3}}, + {L"\U00000900\U00000600", {2304, 1536}, {1, 2}}, + {L"\U00000900\U00000308\U00000600", {2304, 1536}, {2, 3}}, + {L"\U00000900\U00000a03", {2304}, {2}}, + {L"\U00000900\U00000308\U00000a03", {2304}, {3}}, + {L"\U00000900\U00001100", {2304, 4352}, {1, 2}}, + {L"\U00000900\U00000308\U00001100", {2304, 4352}, {2, 3}}, + {L"\U00000900\U00001160", {2304, 4448}, {1, 2}}, + {L"\U00000900\U00000308\U00001160", {2304, 4448}, {2, 3}}, + {L"\U00000900\U000011a8", {2304, 4520}, {1, 2}}, + {L"\U00000900\U00000308\U000011a8", {2304, 4520}, {2, 3}}, + {L"\U00000900\U0000ac00", {2304, 44032}, {1, 2}}, + {L"\U00000900\U00000308\U0000ac00", {2304, 44032}, {2, 3}}, + {L"\U00000900\U0000ac01", {2304, 44033}, {1, 2}}, + {L"\U00000900\U00000308\U0000ac01", {2304, 44033}, {2, 3}}, + {L"\U00000900\U00000903", {2304}, {2}}, + {L"\U00000900\U00000308\U00000903", {2304}, {3}}, + {L"\U00000900\U00000904", {2304, 2308}, {1, 2}}, + {L"\U00000900\U00000308\U00000904", {2304, 2308}, {2, 3}}, + {L"\U00000900\U00000d4e", {2304, 3406}, {1, 2}}, + {L"\U00000900\U00000308\U00000d4e", {2304, 3406}, {2, 3}}, + {L"\U00000900\U00000915", {2304, 2325}, {1, 2}}, + {L"\U00000900\U00000308\U00000915", {2304, 2325}, {2, 3}}, + {L"\U00000900\U0000231a", {2304, 8986}, {1, 2}}, + {L"\U00000900\U00000308\U0000231a", {2304, 8986}, {2, 3}}, + {L"\U00000900\U00000300", {2304}, {2}}, + {L"\U00000900\U00000308\U00000300", {2304}, {3}}, + {L"\U00000900\U00000900", {2304}, {2}}, + {L"\U00000900\U00000308\U00000900", {2304}, {3}}, + {L"\U00000900\U0000094d", {2304}, {2}}, + {L"\U00000900\U00000308\U0000094d", {2304}, {3}}, + {L"\U00000900\U0000200d", {2304}, {2}}, + {L"\U00000900\U00000308\U0000200d", {2304}, {3}}, + {L"\U00000900\U00000378", {2304, 888}, {1, 2}}, + {L"\U00000900\U00000308\U00000378", {2304, 888}, {2, 3}}, {L"\U0000094d\U00000020", {2381, 32}, {1, 2}}, {L"\U0000094d\U00000308\U00000020", {2381, 32}, {2, 3}}, {L"\U0000094d\U0000000d", {2381, 13}, {1, 2}}, @@ -3488,8 +3212,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000094d\U00000308\U0000000a", {2381, 10}, {2, 3}}, {L"\U0000094d\U00000001", {2381, 1}, {1, 2}}, {L"\U0000094d\U00000308\U00000001", {2381, 1}, {2, 3}}, - {L"\U0000094d\U0000034f", {2381}, {2}}, - {L"\U0000094d\U00000308\U0000034f", {2381}, {3}}, + {L"\U0000094d\U0000200c", {2381}, {2}}, + {L"\U0000094d\U00000308\U0000200c", {2381}, {3}}, {L"\U0000094d\U0001f1e6", {2381, 127462}, {1, 2}}, {L"\U0000094d\U00000308\U0001f1e6", {2381, 127462}, {2, 3}}, {L"\U0000094d\U00000600", {2381, 1536}, {1, 2}}, @@ -3506,8 +3230,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000094d\U00000308\U0000ac00", {2381, 44032}, {2, 3}}, {L"\U0000094d\U0000ac01", {2381, 44033}, {1, 2}}, {L"\U0000094d\U00000308\U0000ac01", {2381, 44033}, {2, 3}}, - {L"\U0000094d\U00000900", {2381}, {2}}, - {L"\U0000094d\U00000308\U00000900", {2381}, {3}}, {L"\U0000094d\U00000903", {2381}, {2}}, {L"\U0000094d\U00000308\U00000903", {2381}, {3}}, {L"\U0000094d\U00000904", {2381, 2308}, {1, 2}}, @@ -3520,8 +3242,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000094d\U00000308\U0000231a", {2381, 8986}, {2, 3}}, {L"\U0000094d\U00000300", {2381}, {2}}, {L"\U0000094d\U00000308\U00000300", {2381}, {3}}, - {L"\U0000094d\U0000093c", {2381}, {2}}, - {L"\U0000094d\U00000308\U0000093c", {2381}, {3}}, + {L"\U0000094d\U00000900", {2381}, {2}}, + {L"\U0000094d\U00000308\U00000900", {2381}, {3}}, {L"\U0000094d\U0000094d", {2381}, {2}}, {L"\U0000094d\U00000308\U0000094d", {2381}, {3}}, {L"\U0000094d\U0000200d", {2381}, {2}}, @@ -3536,8 +3258,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000200d\U00000308\U0000000a", {8205, 10}, {2, 3}}, {L"\U0000200d\U00000001", {8205, 1}, {1, 2}}, {L"\U0000200d\U00000308\U00000001", {8205, 1}, {2, 3}}, - {L"\U0000200d\U0000034f", {8205}, {2}}, - {L"\U0000200d\U00000308\U0000034f", {8205}, {3}}, + {L"\U0000200d\U0000200c", {8205}, {2}}, + {L"\U0000200d\U00000308\U0000200c", {8205}, {3}}, {L"\U0000200d\U0001f1e6", {8205, 127462}, {1, 2}}, {L"\U0000200d\U00000308\U0001f1e6", {8205, 127462}, {2, 3}}, {L"\U0000200d\U00000600", {8205, 1536}, {1, 2}}, @@ -3554,8 +3276,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000200d\U00000308\U0000ac00", {8205, 44032}, {2, 3}}, {L"\U0000200d\U0000ac01", {8205, 44033}, {1, 2}}, {L"\U0000200d\U00000308\U0000ac01", {8205, 44033}, {2, 3}}, - {L"\U0000200d\U00000900", {8205}, {2}}, - {L"\U0000200d\U00000308\U00000900", {8205}, {3}}, {L"\U0000200d\U00000903", {8205}, {2}}, {L"\U0000200d\U00000308\U00000903", {8205}, {3}}, {L"\U0000200d\U00000904", {8205, 2308}, {1, 2}}, @@ -3568,8 +3288,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000200d\U00000308\U0000231a", {8205, 8986}, {2, 3}}, {L"\U0000200d\U00000300", {8205}, {2}}, {L"\U0000200d\U00000308\U00000300", {8205}, {3}}, - {L"\U0000200d\U0000093c", {8205}, {2}}, - {L"\U0000200d\U00000308\U0000093c", {8205}, {3}}, + {L"\U0000200d\U00000900", {8205}, {2}}, + {L"\U0000200d\U00000308\U00000900", {8205}, {3}}, {L"\U0000200d\U0000094d", {8205}, {2}}, {L"\U0000200d\U00000308\U0000094d", {8205}, {3}}, {L"\U0000200d\U0000200d", {8205}, {2}}, @@ -3584,8 +3304,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000378\U00000308\U0000000a", {888, 10}, {2, 3}}, {L"\U00000378\U00000001", {888, 1}, {1, 2}}, {L"\U00000378\U00000308\U00000001", {888, 1}, {2, 3}}, - {L"\U00000378\U0000034f", {888}, {2}}, - {L"\U00000378\U00000308\U0000034f", {888}, {3}}, + {L"\U00000378\U0000200c", {888}, {2}}, + {L"\U00000378\U00000308\U0000200c", {888}, {3}}, {L"\U00000378\U0001f1e6", {888, 127462}, {1, 2}}, {L"\U00000378\U00000308\U0001f1e6", {888, 127462}, {2, 3}}, {L"\U00000378\U00000600", {888, 1536}, {1, 2}}, @@ -3602,8 +3322,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000378\U00000308\U0000ac00", {888, 44032}, {2, 3}}, {L"\U00000378\U0000ac01", {888, 44033}, {1, 2}}, {L"\U00000378\U00000308\U0000ac01", {888, 44033}, {2, 3}}, - {L"\U00000378\U00000900", {888}, {2}}, - {L"\U00000378\U00000308\U00000900", {888}, {3}}, {L"\U00000378\U00000903", {888}, {2}}, {L"\U00000378\U00000308\U00000903", {888}, {3}}, {L"\U00000378\U00000904", {888, 2308}, {1, 2}}, @@ -3616,8 +3334,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000378\U00000308\U0000231a", {888, 8986}, {2, 3}}, {L"\U00000378\U00000300", {888}, {2}}, {L"\U00000378\U00000308\U00000300", {888}, {3}}, - {L"\U00000378\U0000093c", {888}, {2}}, - {L"\U00000378\U00000308\U0000093c", {888}, {3}}, + {L"\U00000378\U00000900", {888}, {2}}, + {L"\U00000378\U00000308\U00000900", {888}, {3}}, {L"\U00000378\U0000094d", {888}, {2}}, {L"\U00000378\U00000308\U0000094d", {888}, {3}}, {L"\U00000378\U0000200d", {888}, {2}}, diff --git a/libcxx/utils/data/unicode/DerivedCoreProperties.txt b/libcxx/utils/data/unicode/DerivedCoreProperties.txt index 220c55685d4b0b..1075638f1a654e 100644 --- a/libcxx/utils/data/unicode/DerivedCoreProperties.txt +++ b/libcxx/utils/data/unicode/DerivedCoreProperties.txt @@ -1,8 +1,8 @@ -# DerivedCoreProperties-15.1.0.txt -# Date: 2023-08-07, 15:21:24 GMT -# © 2023 Unicode®, Inc. +# DerivedCoreProperties-16.0.0.txt +# Date: 2024-05-31, 18:09:32 GMT +# © 2024 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database # For documentation, see https://www.unicode.org/reports/tr44/ @@ -177,6 +177,7 @@ FF5C ; Math # Sm FULLWIDTH VERTICAL LINE FF5E ; Math # Sm FULLWIDTH TILDE FFE2 ; Math # Sm FULLWIDTH NOT SIGN FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW +10D8E..10D8F ; Math # Sm [2] GARAY PLUS SIGN..GARAY MINUS SIGN 1D400..1D454 ; Math # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G 1D456..1D49C ; Math # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A 1D49E..1D49F ; Math # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D @@ -253,7 +254,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 1EEAB..1EEBB ; Math # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 1EEF0..1EEF1 ; Math # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL -# Total code points: 2310 +# Total code points: 2312 # ================================================ @@ -280,6 +281,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 02EC ; Alphabetic # Lm MODIFIER LETTER VOICING 02EE ; Alphabetic # Lm MODIFIER LETTER DOUBLE APOSTROPHE 0345 ; Alphabetic # Mn COMBINING GREEK YPOGEGRAMMENI +0363..036F ; Alphabetic # Mn [13] COMBINING LATIN SMALL LETTER A..COMBINING LATIN SMALL LETTER X 0370..0373 ; Alphabetic # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI 0374 ; Alphabetic # Lm GREEK NUMERAL SIGN 0376..0377 ; Alphabetic # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA @@ -343,6 +345,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 0860..086A ; Alphabetic # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 0870..0887 ; Alphabetic # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT 0889..088E ; Alphabetic # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL +0897 ; Alphabetic # Mn ARABIC PEPET 08A0..08C8 ; Alphabetic # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; Alphabetic # Lm ARABIC SMALL FARSI YEH 08D4..08DF ; Alphabetic # Mn [12] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH WORD WAQFA @@ -710,7 +713,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 1C4D..1C4F ; Alphabetic # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA 1C5A..1C77 ; Alphabetic # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; Alphabetic # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD -1C80..1C88 ; Alphabetic # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; Alphabetic # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; Alphabetic # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Alphabetic # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CE9..1CEC ; Alphabetic # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL @@ -723,7 +726,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 1D78 ; Alphabetic # Lm MODIFIER LETTER CYRILLIC EN 1D79..1D9A ; Alphabetic # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK 1D9B..1DBF ; Alphabetic # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA -1DE7..1DF4 ; Alphabetic # Mn [14] COMBINING LATIN SMALL LETTER ALPHA..COMBINING LATIN SMALL LETTER U WITH DIAERESIS +1DD3..1DF4 ; Alphabetic # Mn [34] COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE..COMBINING LATIN SMALL LETTER U WITH DIAERESIS 1E00..1F15 ; Alphabetic # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA 1F18..1F1D ; Alphabetic # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA 1F20..1F45 ; Alphabetic # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA @@ -830,10 +833,10 @@ A771..A787 ; Alphabetic # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER A788 ; Alphabetic # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; Alphabetic # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; Alphabetic # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; Alphabetic # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; Alphabetic # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; Alphabetic # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; Alphabetic # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; Alphabetic # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; Alphabetic # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; Alphabetic # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; Alphabetic # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; Alphabetic # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -998,6 +1001,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 105A3..105B1 ; Alphabetic # L& [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; Alphabetic # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; Alphabetic # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; Alphabetic # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; Alphabetic # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; Alphabetic # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; Alphabetic # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -1038,9 +1042,18 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 10CC0..10CF2 ; Alphabetic # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US 10D00..10D23 ; Alphabetic # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA 10D24..10D27 ; Alphabetic # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D4A..10D4D ; Alphabetic # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; Alphabetic # Lm GARAY VOWEL LENGTH MARK +10D4F ; Alphabetic # Lo GARAY SUKUN +10D50..10D65 ; Alphabetic # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D69 ; Alphabetic # Mn GARAY VOWEL SIGN E +10D6F ; Alphabetic # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; Alphabetic # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 10E80..10EA9 ; Alphabetic # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EAB..10EAC ; Alphabetic # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK 10EB0..10EB1 ; Alphabetic # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10EC2..10EC4 ; Alphabetic # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW +10EFC ; Alphabetic # Mn ARABIC COMBINING ALEF OVERLAY 10F00..10F1C ; Alphabetic # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; Alphabetic # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; Alphabetic # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -1121,6 +1134,19 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 11357 ; Alphabetic # Mc GRANTHA AU LENGTH MARK 1135D..11361 ; Alphabetic # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL 11362..11363 ; Alphabetic # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +11380..11389 ; Alphabetic # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; Alphabetic # Lo TULU-TIGALARI LETTER EE +1138E ; Alphabetic # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; Alphabetic # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; Alphabetic # Lo TULU-TIGALARI SIGN AVAGRAHA +113B8..113BA ; Alphabetic # Mc [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II +113BB..113C0 ; Alphabetic # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113C2 ; Alphabetic # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; Alphabetic # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113CA ; Alphabetic # Mc [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; Alphabetic # Mc [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA +113D1 ; Alphabetic # Lo TULU-TIGALARI REPHA +113D3 ; Alphabetic # Lo TULU-TIGALARI SIGN PLUTA 11400..11434 ; Alphabetic # Lo [53] NEWA LETTER A..NEWA LETTER HA 11435..11437 ; Alphabetic # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11438..1143F ; Alphabetic # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI @@ -1163,7 +1189,9 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 116B0..116B5 ; Alphabetic # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU 116B8 ; Alphabetic # Lo TAKRI LETTER ARCHAIC KHA 11700..1171A ; Alphabetic # Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA -1171D..1171F ; Alphabetic # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; Alphabetic # Mn AHOM CONSONANT SIGN MEDIAL LA +1171E ; Alphabetic # Mc AHOM CONSONANT SIGN MEDIAL RA +1171F ; Alphabetic # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11720..11721 ; Alphabetic # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11722..11725 ; Alphabetic # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11726 ; Alphabetic # Mc AHOM VOWEL SIGN E @@ -1211,6 +1239,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 11A97 ; Alphabetic # Mc SOYOMBO SIGN VISARGA 11A9D ; Alphabetic # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; Alphabetic # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; Alphabetic # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO 11C00..11C08 ; Alphabetic # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; Alphabetic # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C2F ; Alphabetic # Mc BHAIKSUKI VOWEL SIGN AA @@ -1264,7 +1293,12 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 12F90..12FF0 ; Alphabetic # Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 13000..1342F ; Alphabetic # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D 13441..13446 ; Alphabetic # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN +13460..143FA ; Alphabetic # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; Alphabetic # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; Alphabetic # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA +1611E..16129 ; Alphabetic # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612A..1612C ; Alphabetic # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA +1612D..1612E ; Alphabetic # Mn [2] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA CONSONANT SIGN MEDIAL RA 16800..16A38 ; Alphabetic # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; Alphabetic # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A70..16ABE ; Alphabetic # Lo [79] TANGSA LETTER OZ..TANGSA LETTER ZA @@ -1273,6 +1307,9 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 16B40..16B43 ; Alphabetic # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM 16B63..16B77 ; Alphabetic # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; Alphabetic # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; Alphabetic # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; Alphabetic # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; Alphabetic # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16E40..16E7F ; Alphabetic # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16F00..16F4A ; Alphabetic # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F4F ; Alphabetic # Mn MIAO SIGN CONSONANT MODIFIER BAR @@ -1285,7 +1322,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 16FF0..16FF1 ; Alphabetic # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY 17000..187F7 ; Alphabetic # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; Alphabetic # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; Alphabetic # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; Alphabetic # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; Alphabetic # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; Alphabetic # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; Alphabetic # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -1348,6 +1385,8 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 1E2C0..1E2EB ; Alphabetic # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH 1E4D0..1E4EA ; Alphabetic # Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL 1E4EB ; Alphabetic # Lm NAG MUNDARI SIGN OJOD +1E5D0..1E5ED ; Alphabetic # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5F0 ; Alphabetic # Lo OL ONAL SIGN HODDOND 1E7E0..1E7E6 ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; Alphabetic # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; Alphabetic # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -1402,7 +1441,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 30000..3134A ; Alphabetic # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A 31350..323AF ; Alphabetic # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF -# Total code points: 138387 +# Total code points: 142759 # ================================================ @@ -1691,6 +1730,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 10FD..10FF ; Lowercase # L& [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN 13F8..13FD ; Lowercase # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV 1C80..1C88 ; Lowercase # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C8A ; Lowercase # L& CYRILLIC SMALL LETTER TJE 1D00..1D2B ; Lowercase # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL 1D2C..1D6A ; Lowercase # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI 1D6B..1D77 ; Lowercase # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G @@ -2032,11 +2072,13 @@ A7C1 ; Lowercase # L& LATIN SMALL LETTER OLD POLISH O A7C3 ; Lowercase # L& LATIN SMALL LETTER ANGLICANA W A7C8 ; Lowercase # L& LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY A7CA ; Lowercase # L& LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7CD ; Lowercase # L& LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D1 ; Lowercase # L& LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; Lowercase # L& LATIN SMALL LETTER DOUBLE THORN A7D5 ; Lowercase # L& LATIN SMALL LETTER DOUBLE WYNN A7D7 ; Lowercase # L& LATIN SMALL LETTER MIDDLE SCOTS S A7D9 ; Lowercase # L& LATIN SMALL LETTER SIGMOID S +A7DB ; Lowercase # L& LATIN SMALL LETTER LAMBDA A7F2..A7F4 ; Lowercase # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F6 ; Lowercase # L& LATIN SMALL LETTER REVERSED HALF H A7F8..A7F9 ; Lowercase # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -2060,6 +2102,7 @@ FF41..FF5A ; Lowercase # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 10787..107B0 ; Lowercase # Lm [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK 107B2..107BA ; Lowercase # Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL 10CC0..10CF2 ; Lowercase # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D70..10D85 ; Lowercase # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118C0..118DF ; Lowercase # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E60..16E7F ; Lowercase # L& [32] MEDEFAIDRIN SMALL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1D41A..1D433 ; Lowercase # L& [26] MATHEMATICAL BOLD SMALL A..MATHEMATICAL BOLD SMALL Z @@ -2096,7 +2139,7 @@ FF41..FF5A ; Lowercase # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 1E030..1E06D ; Lowercase # Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE 1E922..1E943 ; Lowercase # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 2544 +# Total code points: 2569 # ================================================ @@ -2379,6 +2422,7 @@ FF41..FF5A ; Lowercase # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 10C7 ; Uppercase # L& GEORGIAN CAPITAL LETTER YN 10CD ; Uppercase # L& GEORGIAN CAPITAL LETTER AEN 13A0..13F5 ; Uppercase # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV +1C89 ; Uppercase # L& CYRILLIC CAPITAL LETTER TJE 1C90..1CBA ; Uppercase # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Uppercase # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1E00 ; Uppercase # L& LATIN CAPITAL LETTER A WITH RING BELOW @@ -2705,9 +2749,12 @@ A7C0 ; Uppercase # L& LATIN CAPITAL LETTER OLD POLISH O A7C2 ; Uppercase # L& LATIN CAPITAL LETTER ANGLICANA W A7C4..A7C7 ; Uppercase # L& [4] LATIN CAPITAL LETTER C WITH PALATAL HOOK..LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9 ; Uppercase # L& LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY +A7CB..A7CC ; Uppercase # L& [2] LATIN CAPITAL LETTER RAMS HORN..LATIN CAPITAL LETTER S WITH DIAGONAL STROKE A7D0 ; Uppercase # L& LATIN CAPITAL LETTER CLOSED INSULAR G A7D6 ; Uppercase # L& LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8 ; Uppercase # L& LATIN CAPITAL LETTER SIGMOID S +A7DA ; Uppercase # L& LATIN CAPITAL LETTER LAMBDA +A7DC ; Uppercase # L& LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F5 ; Uppercase # L& LATIN CAPITAL LETTER REVERSED HALF H FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z 10400..10427 ; Uppercase # L& [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW @@ -2717,6 +2764,7 @@ FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH 1058C..10592 ; Uppercase # L& [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE 10594..10595 ; Uppercase # L& [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE 10C80..10CB2 ; Uppercase # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10D50..10D65 ; Uppercase # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA 118A0..118BF ; Uppercase # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 16E40..16E5F ; Uppercase # L& [32] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN CAPITAL LETTER Y 1D400..1D419 ; Uppercase # L& [26] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL BOLD CAPITAL Z @@ -2755,7 +2803,7 @@ FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH 1F150..1F169 ; Uppercase # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F170..1F189 ; Uppercase # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 1951 +# Total code points: 1978 # ================================================ @@ -2800,7 +2848,7 @@ FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH 10FD..10FF ; Cased # L& [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN 13A0..13F5 ; Cased # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV 13F8..13FD ; Cased # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV -1C80..1C88 ; Cased # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; Cased # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; Cased # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Cased # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1D00..1D2B ; Cased # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL @@ -2863,10 +2911,10 @@ A722..A76F ; Cased # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN A770 ; Cased # Lm MODIFIER LETTER US A771..A787 ; Cased # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T A78B..A78E ; Cased # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT -A790..A7CA ; Cased # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; Cased # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; Cased # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; Cased # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; Cased # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; Cased # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; Cased # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; Cased # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F8..A7F9 ; Cased # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -2897,6 +2945,8 @@ FF41..FF5A ; Cased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 107B2..107BA ; Cased # Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL 10C80..10CB2 ; Cased # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US 10CC0..10CF2 ; Cased # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D50..10D65 ; Cased # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D70..10D85 ; Cased # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118A0..118DF ; Cased # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E40..16E7F ; Cased # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1D400..1D454 ; Cased # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G @@ -2938,7 +2988,7 @@ FF41..FF5A ; Cased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 1F150..1F169 ; Cased # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F170..1F189 ; Cased # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 4526 +# Total code points: 4578 # ================================================ @@ -3015,7 +3065,7 @@ FF41..FF5A ; Cased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 0859..085B ; Case_Ignorable # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK 0888 ; Case_Ignorable # Sk ARABIC RAISED ROUND DOT 0890..0891 ; Case_Ignorable # Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE -0898..089F ; Case_Ignorable # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; Case_Ignorable # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08C9 ; Case_Ignorable # Lm ARABIC SMALL FARSI YEH 08CA..08E1 ; Case_Ignorable # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA 08E2 ; Case_Ignorable # Cf ARABIC DISPUTED END OF AYAH @@ -3296,8 +3346,11 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 10A3F ; Case_Ignorable # Mn KHAROSHTHI VIRAMA 10AE5..10AE6 ; Case_Ignorable # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW 10D24..10D27 ; Case_Ignorable # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D4E ; Case_Ignorable # Lm GARAY VOWEL LENGTH MARK +10D69..10D6D ; Case_Ignorable # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK +10D6F ; Case_Ignorable # Lm GARAY REDUPLICATION MARK 10EAB..10EAC ; Case_Ignorable # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK -10EFD..10EFF ; Case_Ignorable # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EFC..10EFF ; Case_Ignorable # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F46..10F50 ; Case_Ignorable # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW 10F82..10F85 ; Case_Ignorable # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW 11001 ; Case_Ignorable # Mn BRAHMI SIGN ANUSVARA @@ -3330,6 +3383,11 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 11340 ; Case_Ignorable # Mn GRANTHA VOWEL SIGN II 11366..1136C ; Case_Ignorable # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; Case_Ignorable # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +113BB..113C0 ; Case_Ignorable # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113CE ; Case_Ignorable # Mn TULU-TIGALARI SIGN VIRAMA +113D0 ; Case_Ignorable # Mn TULU-TIGALARI CONJOINER +113D2 ; Case_Ignorable # Mn TULU-TIGALARI GEMINATION MARK +113E1..113E2 ; Case_Ignorable # Mn [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11438..1143F ; Case_Ignorable # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI 11442..11444 ; Case_Ignorable # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA 11446 ; Case_Ignorable # Mn NEWA SIGN NUKTA @@ -3349,7 +3407,8 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 116AD ; Case_Ignorable # Mn TAKRI VOWEL SIGN AA 116B0..116B5 ; Case_Ignorable # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU 116B7 ; Case_Ignorable # Mn TAKRI SIGN NUKTA -1171D..1171F ; Case_Ignorable # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; Case_Ignorable # Mn AHOM CONSONANT SIGN MEDIAL LA +1171F ; Case_Ignorable # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11722..11725 ; Case_Ignorable # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11727..1172B ; Case_Ignorable # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER 1182F..11837 ; Case_Ignorable # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA @@ -3388,12 +3447,17 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 11F36..11F3A ; Case_Ignorable # Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R 11F40 ; Case_Ignorable # Mn KAWI VOWEL SIGN EU 11F42 ; Case_Ignorable # Mn KAWI CONJOINER +11F5A ; Case_Ignorable # Mn KAWI SIGN NUKTA 13430..1343F ; Case_Ignorable # Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE 13440 ; Case_Ignorable # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13447..13455 ; Case_Ignorable # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +1611E..16129 ; Case_Ignorable # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612D..1612F ; Case_Ignorable # Mn [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA 16AF0..16AF4 ; Case_Ignorable # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; Case_Ignorable # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16B40..16B43 ; Case_Ignorable # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM +16D40..16D42 ; Case_Ignorable # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D6B..16D6C ; Case_Ignorable # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16F4F ; Case_Ignorable # Mn MIAO SIGN CONSONANT MODIFIER BAR 16F8F..16F92 ; Case_Ignorable # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16F93..16F9F ; Case_Ignorable # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 @@ -3432,6 +3496,7 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 1E2EC..1E2EF ; Case_Ignorable # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI 1E4EB ; Case_Ignorable # Lm NAG MUNDARI SIGN OJOD 1E4EC..1E4EF ; Case_Ignorable # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH +1E5EE..1E5EF ; Case_Ignorable # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR 1E8D0..1E8D6 ; Case_Ignorable # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS 1E944..1E94A ; Case_Ignorable # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA 1E94B ; Case_Ignorable # Lm ADLAM NASALIZATION MARK @@ -3440,7 +3505,7 @@ E0001 ; Case_Ignorable # Cf LANGUAGE TAG E0020..E007F ; Case_Ignorable # Cf [96] TAG SPACE..CANCEL TAG E0100..E01EF ; Case_Ignorable # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 2707 +# Total code points: 2749 # ================================================ @@ -3724,6 +3789,7 @@ E0100..E01EF ; Case_Ignorable # Mn [240] VARIATION SELECTOR-17..VARIATION SELEC 10C7 ; Changes_When_Lowercased # L& GEORGIAN CAPITAL LETTER YN 10CD ; Changes_When_Lowercased # L& GEORGIAN CAPITAL LETTER AEN 13A0..13F5 ; Changes_When_Lowercased # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV +1C89 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER TJE 1C90..1CBA ; Changes_When_Lowercased # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Changes_When_Lowercased # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1E00 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH RING BELOW @@ -4043,9 +4109,12 @@ A7C0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER OLD POLI A7C2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER ANGLICANA W A7C4..A7C7 ; Changes_When_Lowercased # L& [4] LATIN CAPITAL LETTER C WITH PALATAL HOOK..LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY +A7CB..A7CC ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER RAMS HORN..LATIN CAPITAL LETTER S WITH DIAGONAL STROKE A7D0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER CLOSED INSULAR G A7D6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER SIGMOID S +A7DA ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER LAMBDA +A7DC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F5 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER REVERSED HALF H FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z 10400..10427 ; Changes_When_Lowercased # L& [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW @@ -4055,11 +4124,12 @@ FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTE 1058C..10592 ; Changes_When_Lowercased # L& [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE 10594..10595 ; Changes_When_Lowercased # L& [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE 10C80..10CB2 ; Changes_When_Lowercased # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10D50..10D65 ; Changes_When_Lowercased # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA 118A0..118BF ; Changes_When_Lowercased # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 16E40..16E5F ; Changes_When_Lowercased # L& [32] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN CAPITAL LETTER Y 1E900..1E921 ; Changes_When_Lowercased # L& [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA -# Total code points: 1433 +# Total code points: 1460 # ================================================ @@ -4140,7 +4210,7 @@ FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTE 018C ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH TOPBAR 0192 ; Changes_When_Uppercased # L& LATIN SMALL LETTER F WITH HOOK 0195 ; Changes_When_Uppercased # L& LATIN SMALL LETTER HV -0199..019A ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER L WITH BAR +0199..019B ; Changes_When_Uppercased # L& [3] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER LAMBDA WITH STROKE 019E ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH LONG RIGHT LEG 01A1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH HORN 01A3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER OI @@ -4216,8 +4286,7 @@ FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTE 0259 ; Changes_When_Uppercased # L& LATIN SMALL LETTER SCHWA 025B..025C ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER OPEN E..LATIN SMALL LETTER REVERSED OPEN E 0260..0261 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER G WITH HOOK..LATIN SMALL LETTER SCRIPT G -0263 ; Changes_When_Uppercased # L& LATIN SMALL LETTER GAMMA -0265..0266 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER TURNED H..LATIN SMALL LETTER H WITH HOOK +0263..0266 ; Changes_When_Uppercased # L& [4] LATIN SMALL LETTER GAMMA..LATIN SMALL LETTER H WITH HOOK 0268..026C ; Changes_When_Uppercased # L& [5] LATIN SMALL LETTER I WITH STROKE..LATIN SMALL LETTER L WITH BELT 026F ; Changes_When_Uppercased # L& LATIN SMALL LETTER TURNED M 0271..0272 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER M WITH HOOK..LATIN SMALL LETTER N WITH LEFT HOOK @@ -4357,6 +4426,7 @@ FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTE 10FD..10FF ; Changes_When_Uppercased # L& [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN 13F8..13FD ; Changes_When_Uppercased # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV 1C80..1C88 ; Changes_When_Uppercased # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C8A ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER TJE 1D79 ; Changes_When_Uppercased # L& LATIN SMALL LETTER INSULAR G 1D7D ; Changes_When_Uppercased # L& LATIN SMALL LETTER P WITH STROKE 1D8E ; Changes_When_Uppercased # L& LATIN SMALL LETTER Z WITH PALATAL HOOK @@ -4676,9 +4746,11 @@ A7C1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER OLD POLISH A7C3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER ANGLICANA W A7C8 ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY A7CA ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7CD ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER CLOSED INSULAR G A7D7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER MIDDLE SCOTS S A7D9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER SIGMOID S +A7DB ; Changes_When_Uppercased # L& LATIN SMALL LETTER LAMBDA A7F6 ; Changes_When_Uppercased # L& LATIN SMALL LETTER REVERSED HALF H AB53 ; Changes_When_Uppercased # L& LATIN SMALL LETTER CHI AB70..ABBF ; Changes_When_Uppercased # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA @@ -4692,11 +4764,12 @@ FF41..FF5A ; Changes_When_Uppercased # L& [26] FULLWIDTH LATIN SMALL LETTER 105B3..105B9 ; Changes_When_Uppercased # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; Changes_When_Uppercased # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE 10CC0..10CF2 ; Changes_When_Uppercased # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D70..10D85 ; Changes_When_Uppercased # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118C0..118DF ; Changes_When_Uppercased # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E60..16E7F ; Changes_When_Uppercased # L& [32] MEDEFAIDRIN SMALL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1E922..1E943 ; Changes_When_Uppercased # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 1525 +# Total code points: 1552 # ================================================ @@ -4777,7 +4850,7 @@ FF41..FF5A ; Changes_When_Uppercased # L& [26] FULLWIDTH LATIN SMALL LETTER 018C ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH TOPBAR 0192 ; Changes_When_Titlecased # L& LATIN SMALL LETTER F WITH HOOK 0195 ; Changes_When_Titlecased # L& LATIN SMALL LETTER HV -0199..019A ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER L WITH BAR +0199..019B ; Changes_When_Titlecased # L& [3] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER LAMBDA WITH STROKE 019E ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH LONG RIGHT LEG 01A1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH HORN 01A3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER OI @@ -4854,8 +4927,7 @@ FF41..FF5A ; Changes_When_Uppercased # L& [26] FULLWIDTH LATIN SMALL LETTER 0259 ; Changes_When_Titlecased # L& LATIN SMALL LETTER SCHWA 025B..025C ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER OPEN E..LATIN SMALL LETTER REVERSED OPEN E 0260..0261 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER G WITH HOOK..LATIN SMALL LETTER SCRIPT G -0263 ; Changes_When_Titlecased # L& LATIN SMALL LETTER GAMMA -0265..0266 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER TURNED H..LATIN SMALL LETTER H WITH HOOK +0263..0266 ; Changes_When_Titlecased # L& [4] LATIN SMALL LETTER GAMMA..LATIN SMALL LETTER H WITH HOOK 0268..026C ; Changes_When_Titlecased # L& [5] LATIN SMALL LETTER I WITH STROKE..LATIN SMALL LETTER L WITH BELT 026F ; Changes_When_Titlecased # L& LATIN SMALL LETTER TURNED M 0271..0272 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER M WITH HOOK..LATIN SMALL LETTER N WITH LEFT HOOK @@ -4993,6 +5065,7 @@ FF41..FF5A ; Changes_When_Uppercased # L& [26] FULLWIDTH LATIN SMALL LETTER 0561..0587 ; Changes_When_Titlecased # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN 13F8..13FD ; Changes_When_Titlecased # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV 1C80..1C88 ; Changes_When_Titlecased # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C8A ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER TJE 1D79 ; Changes_When_Titlecased # L& LATIN SMALL LETTER INSULAR G 1D7D ; Changes_When_Titlecased # L& LATIN SMALL LETTER P WITH STROKE 1D8E ; Changes_When_Titlecased # L& LATIN SMALL LETTER Z WITH PALATAL HOOK @@ -5312,9 +5385,11 @@ A7C1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER OLD POLISH A7C3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER ANGLICANA W A7C8 ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY A7CA ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7CD ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER CLOSED INSULAR G A7D7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER MIDDLE SCOTS S A7D9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER SIGMOID S +A7DB ; Changes_When_Titlecased # L& LATIN SMALL LETTER LAMBDA A7F6 ; Changes_When_Titlecased # L& LATIN SMALL LETTER REVERSED HALF H AB53 ; Changes_When_Titlecased # L& LATIN SMALL LETTER CHI AB70..ABBF ; Changes_When_Titlecased # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA @@ -5328,11 +5403,12 @@ FF41..FF5A ; Changes_When_Titlecased # L& [26] FULLWIDTH LATIN SMALL LETTER 105B3..105B9 ; Changes_When_Titlecased # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; Changes_When_Titlecased # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE 10CC0..10CF2 ; Changes_When_Titlecased # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D70..10D85 ; Changes_When_Titlecased # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118C0..118DF ; Changes_When_Titlecased # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E60..16E7F ; Changes_When_Titlecased # L& [32] MEDEFAIDRIN SMALL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1E922..1E943 ; Changes_When_Titlecased # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 1452 +# Total code points: 1479 # ================================================ @@ -5623,7 +5699,7 @@ FF41..FF5A ; Changes_When_Titlecased # L& [26] FULLWIDTH LATIN SMALL LETTER 10C7 ; Changes_When_Casefolded # L& GEORGIAN CAPITAL LETTER YN 10CD ; Changes_When_Casefolded # L& GEORGIAN CAPITAL LETTER AEN 13F8..13FD ; Changes_When_Casefolded # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV -1C80..1C88 ; Changes_When_Casefolded # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C89 ; Changes_When_Casefolded # L& [10] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC CAPITAL LETTER TJE 1C90..1CBA ; Changes_When_Casefolded # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Changes_When_Casefolded # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1E00 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH RING BELOW @@ -5945,9 +6021,12 @@ A7C0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER OLD POLI A7C2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER ANGLICANA W A7C4..A7C7 ; Changes_When_Casefolded # L& [4] LATIN CAPITAL LETTER C WITH PALATAL HOOK..LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY +A7CB..A7CC ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER RAMS HORN..LATIN CAPITAL LETTER S WITH DIAGONAL STROKE A7D0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER CLOSED INSULAR G A7D6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER SIGMOID S +A7DA ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER LAMBDA +A7DC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F5 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER REVERSED HALF H AB70..ABBF ; Changes_When_Casefolded # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA FB00..FB06 ; Changes_When_Casefolded # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST @@ -5960,11 +6039,12 @@ FF21..FF3A ; Changes_When_Casefolded # L& [26] FULLWIDTH LATIN CAPITAL LETTE 1058C..10592 ; Changes_When_Casefolded # L& [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE 10594..10595 ; Changes_When_Casefolded # L& [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE 10C80..10CB2 ; Changes_When_Casefolded # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10D50..10D65 ; Changes_When_Casefolded # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA 118A0..118BF ; Changes_When_Casefolded # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 16E40..16E5F ; Changes_When_Casefolded # L& [32] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN CAPITAL LETTER Y 1E900..1E921 ; Changes_When_Casefolded # L& [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA -# Total code points: 1506 +# Total code points: 1533 # ================================================ @@ -5980,8 +6060,7 @@ FF21..FF3A ; Changes_When_Casefolded # L& [26] FULLWIDTH LATIN CAPITAL LETTE 00D8..00F6 ; Changes_When_Casemapped # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS 00F8..0137 ; Changes_When_Casemapped # L& [64] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER K WITH CEDILLA 0139..018C ; Changes_When_Casemapped # L& [84] LATIN CAPITAL LETTER L WITH ACUTE..LATIN SMALL LETTER D WITH TOPBAR -018E..019A ; Changes_When_Casemapped # L& [13] LATIN CAPITAL LETTER REVERSED E..LATIN SMALL LETTER L WITH BAR -019C..01A9 ; Changes_When_Casemapped # L& [14] LATIN CAPITAL LETTER TURNED M..LATIN CAPITAL LETTER ESH +018E..01A9 ; Changes_When_Casemapped # L& [28] LATIN CAPITAL LETTER REVERSED E..LATIN CAPITAL LETTER ESH 01AC..01B9 ; Changes_When_Casemapped # L& [14] LATIN CAPITAL LETTER T WITH HOOK..LATIN SMALL LETTER EZH REVERSED 01BC..01BD ; Changes_When_Casemapped # L& [2] LATIN CAPITAL LETTER TONE FIVE..LATIN SMALL LETTER TONE FIVE 01BF ; Changes_When_Casemapped # L& LATIN LETTER WYNN @@ -5992,8 +6071,7 @@ FF21..FF3A ; Changes_When_Casefolded # L& [26] FULLWIDTH LATIN CAPITAL LETTE 0259 ; Changes_When_Casemapped # L& LATIN SMALL LETTER SCHWA 025B..025C ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER OPEN E..LATIN SMALL LETTER REVERSED OPEN E 0260..0261 ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER G WITH HOOK..LATIN SMALL LETTER SCRIPT G -0263 ; Changes_When_Casemapped # L& LATIN SMALL LETTER GAMMA -0265..0266 ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER TURNED H..LATIN SMALL LETTER H WITH HOOK +0263..0266 ; Changes_When_Casemapped # L& [4] LATIN SMALL LETTER GAMMA..LATIN SMALL LETTER H WITH HOOK 0268..026C ; Changes_When_Casemapped # L& [5] LATIN SMALL LETTER I WITH STROKE..LATIN SMALL LETTER L WITH BELT 026F ; Changes_When_Casemapped # L& LATIN SMALL LETTER TURNED M 0271..0272 ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER M WITH HOOK..LATIN SMALL LETTER N WITH LEFT HOOK @@ -6027,7 +6105,7 @@ FF21..FF3A ; Changes_When_Casefolded # L& [26] FULLWIDTH LATIN CAPITAL LETTE 10FD..10FF ; Changes_When_Casemapped # L& [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN 13A0..13F5 ; Changes_When_Casemapped # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV 13F8..13FD ; Changes_When_Casemapped # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV -1C80..1C88 ; Changes_When_Casemapped # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; Changes_When_Casemapped # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; Changes_When_Casemapped # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Changes_When_Casemapped # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1D79 ; Changes_When_Casemapped # L& LATIN SMALL LETTER INSULAR G @@ -6078,9 +6156,9 @@ A779..A787 ; Changes_When_Casemapped # L& [15] LATIN CAPITAL LETTER INSULAR A78B..A78D ; Changes_When_Casemapped # L& [3] LATIN CAPITAL LETTER SALTILLO..LATIN CAPITAL LETTER TURNED H A790..A794 ; Changes_When_Casemapped # L& [5] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER C WITH PALATAL HOOK A796..A7AE ; Changes_When_Casemapped # L& [25] LATIN CAPITAL LETTER B WITH FLOURISH..LATIN CAPITAL LETTER SMALL CAPITAL I -A7B0..A7CA ; Changes_When_Casemapped # L& [27] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7B0..A7CD ; Changes_When_Casemapped # L& [30] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; Changes_When_Casemapped # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G -A7D6..A7D9 ; Changes_When_Casemapped # L& [4] LATIN CAPITAL LETTER MIDDLE SCOTS S..LATIN SMALL LETTER SIGMOID S +A7D6..A7DC ; Changes_When_Casemapped # L& [7] LATIN CAPITAL LETTER MIDDLE SCOTS S..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F5..A7F6 ; Changes_When_Casemapped # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H AB53 ; Changes_When_Casemapped # L& LATIN SMALL LETTER CHI AB70..ABBF ; Changes_When_Casemapped # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA @@ -6101,11 +6179,13 @@ FF41..FF5A ; Changes_When_Casemapped # L& [26] FULLWIDTH LATIN SMALL LETTER 105BB..105BC ; Changes_When_Casemapped # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE 10C80..10CB2 ; Changes_When_Casemapped # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US 10CC0..10CF2 ; Changes_When_Casemapped # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D50..10D65 ; Changes_When_Casemapped # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D70..10D85 ; Changes_When_Casemapped # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118A0..118DF ; Changes_When_Casemapped # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E40..16E7F ; Changes_When_Casemapped # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1E900..1E943 ; Changes_When_Casemapped # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 2927 +# Total code points: 2981 # ================================================ @@ -6364,7 +6444,7 @@ FF41..FF5A ; Changes_When_Casemapped # L& [26] FULLWIDTH LATIN SMALL LETTER 1C4D..1C4F ; ID_Start # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA 1C5A..1C77 ; ID_Start # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; ID_Start # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD -1C80..1C88 ; ID_Start # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; ID_Start # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; ID_Start # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; ID_Start # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CE9..1CEC ; ID_Start # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL @@ -6481,10 +6561,10 @@ A771..A787 ; ID_Start # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER I A788 ; ID_Start # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; ID_Start # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; ID_Start # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; ID_Start # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; ID_Start # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; ID_Start # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; ID_Start # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; ID_Start # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; ID_Start # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; ID_Start # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; ID_Start # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; ID_Start # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -6603,6 +6683,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 105A3..105B1 ; ID_Start # L& [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; ID_Start # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; ID_Start # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; ID_Start # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; ID_Start # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; ID_Start # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; ID_Start # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -6639,8 +6720,15 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 10C80..10CB2 ; ID_Start # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US 10CC0..10CF2 ; ID_Start # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US 10D00..10D23 ; ID_Start # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA +10D4A..10D4D ; ID_Start # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; ID_Start # Lm GARAY VOWEL LENGTH MARK +10D4F ; ID_Start # Lo GARAY SUKUN +10D50..10D65 ; ID_Start # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D6F ; ID_Start # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; ID_Start # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 10E80..10EA9 ; ID_Start # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EB0..10EB1 ; ID_Start # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10EC2..10EC4 ; ID_Start # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW 10F00..10F1C ; ID_Start # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; ID_Start # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; ID_Start # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -6679,6 +6767,13 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1133D ; ID_Start # Lo GRANTHA SIGN AVAGRAHA 11350 ; ID_Start # Lo GRANTHA OM 1135D..11361 ; ID_Start # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11380..11389 ; ID_Start # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; ID_Start # Lo TULU-TIGALARI LETTER EE +1138E ; ID_Start # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; ID_Start # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; ID_Start # Lo TULU-TIGALARI SIGN AVAGRAHA +113D1 ; ID_Start # Lo TULU-TIGALARI REPHA +113D3 ; ID_Start # Lo TULU-TIGALARI SIGN PLUTA 11400..11434 ; ID_Start # Lo [53] NEWA LETTER A..NEWA LETTER HA 11447..1144A ; ID_Start # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI 1145F..11461 ; ID_Start # Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA @@ -6713,6 +6808,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 11A5C..11A89 ; ID_Start # Lo [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA 11A9D ; ID_Start # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; ID_Start # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; ID_Start # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO 11C00..11C08 ; ID_Start # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; ID_Start # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C40 ; ID_Start # Lo BHAIKSUKI SIGN AVAGRAHA @@ -6736,7 +6832,9 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 12F90..12FF0 ; ID_Start # Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 13000..1342F ; ID_Start # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D 13441..13446 ; ID_Start # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN +13460..143FA ; ID_Start # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; ID_Start # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; ID_Start # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA 16800..16A38 ; ID_Start # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; ID_Start # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A70..16ABE ; ID_Start # Lo [79] TANGSA LETTER OZ..TANGSA LETTER ZA @@ -6745,6 +6843,9 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 16B40..16B43 ; ID_Start # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM 16B63..16B77 ; ID_Start # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; ID_Start # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; ID_Start # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; ID_Start # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; ID_Start # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16E40..16E7F ; ID_Start # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16F00..16F4A ; ID_Start # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F50 ; ID_Start # Lo MIAO LETTER NASALIZATION @@ -6753,7 +6854,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 16FE3 ; ID_Start # Lm OLD CHINESE ITERATION MARK 17000..187F7 ; ID_Start # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; ID_Start # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; ID_Start # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; ID_Start # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; ID_Start # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; ID_Start # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; ID_Start # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -6809,6 +6910,8 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1E2C0..1E2EB ; ID_Start # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH 1E4D0..1E4EA ; ID_Start # Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL 1E4EB ; ID_Start # Lm NAG MUNDARI SIGN OJOD +1E5D0..1E5ED ; ID_Start # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5F0 ; ID_Start # Lo OL ONAL SIGN HODDOND 1E7E0..1E7E6 ; ID_Start # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; ID_Start # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; ID_Start # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -6859,7 +6962,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 30000..3134A ; ID_Start # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A 31350..323AF ; ID_Start # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF -# Total code points: 136967 +# Total code points: 141269 # ================================================ @@ -6966,7 +7069,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 0860..086A ; ID_Continue # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 0870..0887 ; ID_Continue # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT 0889..088E ; ID_Continue # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL -0898..089F ; ID_Continue # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; ID_Continue # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08A0..08C8 ; ID_Continue # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; ID_Continue # Lm ARABIC SMALL FARSI YEH 08CA..08E1 ; ID_Continue # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA @@ -7399,7 +7502,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1C50..1C59 ; ID_Continue # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE 1C5A..1C77 ; ID_Continue # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; ID_Continue # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD -1C80..1C88 ; ID_Continue # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; ID_Continue # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; ID_Continue # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; ID_Continue # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CD0..1CD2 ; ID_Continue # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA @@ -7543,10 +7646,10 @@ A771..A787 ; ID_Continue # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTE A788 ; ID_Continue # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; ID_Continue # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; ID_Continue # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; ID_Continue # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; ID_Continue # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; ID_Continue # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; ID_Continue # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; ID_Continue # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; ID_Continue # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; ID_Continue # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; ID_Continue # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; ID_Continue # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -7735,6 +7838,7 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 105A3..105B1 ; ID_Continue # L& [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; ID_Continue # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; ID_Continue # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; ID_Continue # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; ID_Continue # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; ID_Continue # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; ID_Continue # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -7779,10 +7883,19 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 10D00..10D23 ; ID_Continue # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA 10D24..10D27 ; ID_Continue # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI 10D30..10D39 ; ID_Continue # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +10D40..10D49 ; ID_Continue # Nd [10] GARAY DIGIT ZERO..GARAY DIGIT NINE +10D4A..10D4D ; ID_Continue # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; ID_Continue # Lm GARAY VOWEL LENGTH MARK +10D4F ; ID_Continue # Lo GARAY SUKUN +10D50..10D65 ; ID_Continue # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D69..10D6D ; ID_Continue # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK +10D6F ; ID_Continue # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; ID_Continue # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 10E80..10EA9 ; ID_Continue # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EAB..10EAC ; ID_Continue # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK 10EB0..10EB1 ; ID_Continue # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE -10EFD..10EFF ; ID_Continue # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EC2..10EC4 ; ID_Continue # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW +10EFC..10EFF ; ID_Continue # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F00..10F1C ; ID_Continue # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; ID_Continue # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; ID_Continue # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -7878,6 +7991,24 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 11362..11363 ; ID_Continue # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C ; ID_Continue # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; ID_Continue # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11380..11389 ; ID_Continue # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; ID_Continue # Lo TULU-TIGALARI LETTER EE +1138E ; ID_Continue # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; ID_Continue # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; ID_Continue # Lo TULU-TIGALARI SIGN AVAGRAHA +113B8..113BA ; ID_Continue # Mc [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II +113BB..113C0 ; ID_Continue # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113C2 ; ID_Continue # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; ID_Continue # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113CA ; ID_Continue # Mc [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; ID_Continue # Mc [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA +113CE ; ID_Continue # Mn TULU-TIGALARI SIGN VIRAMA +113CF ; ID_Continue # Mc TULU-TIGALARI SIGN LOOPED VIRAMA +113D0 ; ID_Continue # Mn TULU-TIGALARI CONJOINER +113D1 ; ID_Continue # Lo TULU-TIGALARI REPHA +113D2 ; ID_Continue # Mn TULU-TIGALARI GEMINATION MARK +113D3 ; ID_Continue # Lo TULU-TIGALARI SIGN PLUTA +113E1..113E2 ; ID_Continue # Mn [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11400..11434 ; ID_Continue # Lo [53] NEWA LETTER A..NEWA LETTER HA 11435..11437 ; ID_Continue # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11438..1143F ; ID_Continue # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI @@ -7929,8 +8060,11 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 116B7 ; ID_Continue # Mn TAKRI SIGN NUKTA 116B8 ; ID_Continue # Lo TAKRI LETTER ARCHAIC KHA 116C0..116C9 ; ID_Continue # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE +116D0..116E3 ; ID_Continue # Nd [20] MYANMAR PAO DIGIT ZERO..MYANMAR EASTERN PWO KAREN DIGIT NINE 11700..1171A ; ID_Continue # Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA -1171D..1171F ; ID_Continue # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; ID_Continue # Mn AHOM CONSONANT SIGN MEDIAL LA +1171E ; ID_Continue # Mc AHOM CONSONANT SIGN MEDIAL RA +1171F ; ID_Continue # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11720..11721 ; ID_Continue # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11722..11725 ; ID_Continue # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11726 ; ID_Continue # Mc AHOM VOWEL SIGN E @@ -7988,6 +8122,8 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 11A98..11A99 ; ID_Continue # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER 11A9D ; ID_Continue # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; ID_Continue # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; ID_Continue # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO +11BF0..11BF9 ; ID_Continue # Nd [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE 11C00..11C08 ; ID_Continue # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; ID_Continue # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C2F ; ID_Continue # Mc BHAIKSUKI VOWEL SIGN AA @@ -8041,6 +8177,7 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 11F41 ; ID_Continue # Mc KAWI SIGN KILLER 11F42 ; ID_Continue # Mn KAWI CONJOINER 11F50..11F59 ; ID_Continue # Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE +11F5A ; ID_Continue # Mn KAWI SIGN NUKTA 11FB0 ; ID_Continue # Lo LISU LETTER YHA 12000..12399 ; ID_Continue # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U 12400..1246E ; ID_Continue # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM @@ -8050,7 +8187,13 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 13440 ; ID_Continue # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13441..13446 ; ID_Continue # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN 13447..13455 ; ID_Continue # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +13460..143FA ; ID_Continue # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; ID_Continue # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; ID_Continue # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA +1611E..16129 ; ID_Continue # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612A..1612C ; ID_Continue # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA +1612D..1612F ; ID_Continue # Mn [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA +16130..16139 ; ID_Continue # Nd [10] GURUNG KHEMA DIGIT ZERO..GURUNG KHEMA DIGIT NINE 16800..16A38 ; ID_Continue # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; ID_Continue # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A60..16A69 ; ID_Continue # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE @@ -8064,6 +8207,10 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 16B50..16B59 ; ID_Continue # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE 16B63..16B77 ; ID_Continue # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; ID_Continue # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; ID_Continue # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; ID_Continue # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; ID_Continue # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT +16D70..16D79 ; ID_Continue # Nd [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE 16E40..16E7F ; ID_Continue # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16F00..16F4A ; ID_Continue # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F4F ; ID_Continue # Mn MIAO SIGN CONSONANT MODIFIER BAR @@ -8077,7 +8224,7 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 16FF0..16FF1 ; ID_Continue # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY 17000..187F7 ; ID_Continue # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; ID_Continue # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; ID_Continue # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; ID_Continue # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; ID_Continue # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; ID_Continue # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; ID_Continue # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -8092,6 +8239,7 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 1BC80..1BC88 ; ID_Continue # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL 1BC90..1BC99 ; ID_Continue # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW 1BC9D..1BC9E ; ID_Continue # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1CCF0..1CCF9 ; ID_Continue # Nd [10] OUTLINED DIGIT ZERO..OUTLINED DIGIT NINE 1CF00..1CF2D ; ID_Continue # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT 1CF30..1CF46 ; ID_Continue # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG 1D165..1D166 ; ID_Continue # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM @@ -8163,6 +8311,10 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 1E4EB ; ID_Continue # Lm NAG MUNDARI SIGN OJOD 1E4EC..1E4EF ; ID_Continue # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH 1E4F0..1E4F9 ; ID_Continue # Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE +1E5D0..1E5ED ; ID_Continue # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5EE..1E5EF ; ID_Continue # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR +1E5F0 ; ID_Continue # Lo OL ONAL SIGN HODDOND +1E5F1..1E5FA ; ID_Continue # Nd [10] OL ONAL DIGIT ZERO..OL ONAL DIGIT NINE 1E7E0..1E7E6 ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; ID_Continue # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; ID_Continue # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -8218,7 +8370,7 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 31350..323AF ; ID_Continue # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF E0100..E01EF ; ID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 140108 +# Total code points: 144541 # ================================================ @@ -8474,7 +8626,7 @@ E0100..E01EF ; ID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR 1C4D..1C4F ; XID_Start # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA 1C5A..1C77 ; XID_Start # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; XID_Start # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD -1C80..1C88 ; XID_Start # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; XID_Start # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; XID_Start # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; XID_Start # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CE9..1CEC ; XID_Start # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL @@ -8590,10 +8742,10 @@ A771..A787 ; XID_Start # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER A788 ; XID_Start # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; XID_Start # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; XID_Start # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; XID_Start # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; XID_Start # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; XID_Start # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; XID_Start # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; XID_Start # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; XID_Start # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; XID_Start # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; XID_Start # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; XID_Start # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -8717,6 +8869,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 105A3..105B1 ; XID_Start # L& [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; XID_Start # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; XID_Start # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; XID_Start # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; XID_Start # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; XID_Start # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; XID_Start # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -8753,8 +8906,15 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 10C80..10CB2 ; XID_Start # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US 10CC0..10CF2 ; XID_Start # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US 10D00..10D23 ; XID_Start # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA +10D4A..10D4D ; XID_Start # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; XID_Start # Lm GARAY VOWEL LENGTH MARK +10D4F ; XID_Start # Lo GARAY SUKUN +10D50..10D65 ; XID_Start # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D6F ; XID_Start # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; XID_Start # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 10E80..10EA9 ; XID_Start # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EB0..10EB1 ; XID_Start # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10EC2..10EC4 ; XID_Start # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW 10F00..10F1C ; XID_Start # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; XID_Start # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; XID_Start # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -8793,6 +8953,13 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 1133D ; XID_Start # Lo GRANTHA SIGN AVAGRAHA 11350 ; XID_Start # Lo GRANTHA OM 1135D..11361 ; XID_Start # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11380..11389 ; XID_Start # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; XID_Start # Lo TULU-TIGALARI LETTER EE +1138E ; XID_Start # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; XID_Start # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; XID_Start # Lo TULU-TIGALARI SIGN AVAGRAHA +113D1 ; XID_Start # Lo TULU-TIGALARI REPHA +113D3 ; XID_Start # Lo TULU-TIGALARI SIGN PLUTA 11400..11434 ; XID_Start # Lo [53] NEWA LETTER A..NEWA LETTER HA 11447..1144A ; XID_Start # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI 1145F..11461 ; XID_Start # Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA @@ -8827,6 +8994,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 11A5C..11A89 ; XID_Start # Lo [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA 11A9D ; XID_Start # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; XID_Start # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; XID_Start # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO 11C00..11C08 ; XID_Start # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; XID_Start # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C40 ; XID_Start # Lo BHAIKSUKI SIGN AVAGRAHA @@ -8850,7 +9018,9 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 12F90..12FF0 ; XID_Start # Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 13000..1342F ; XID_Start # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D 13441..13446 ; XID_Start # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN +13460..143FA ; XID_Start # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; XID_Start # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; XID_Start # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA 16800..16A38 ; XID_Start # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; XID_Start # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A70..16ABE ; XID_Start # Lo [79] TANGSA LETTER OZ..TANGSA LETTER ZA @@ -8859,6 +9029,9 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 16B40..16B43 ; XID_Start # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM 16B63..16B77 ; XID_Start # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; XID_Start # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; XID_Start # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; XID_Start # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; XID_Start # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16E40..16E7F ; XID_Start # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16F00..16F4A ; XID_Start # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F50 ; XID_Start # Lo MIAO LETTER NASALIZATION @@ -8867,7 +9040,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 16FE3 ; XID_Start # Lm OLD CHINESE ITERATION MARK 17000..187F7 ; XID_Start # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; XID_Start # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; XID_Start # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; XID_Start # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; XID_Start # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; XID_Start # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; XID_Start # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -8923,6 +9096,8 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 1E2C0..1E2EB ; XID_Start # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH 1E4D0..1E4EA ; XID_Start # Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL 1E4EB ; XID_Start # Lm NAG MUNDARI SIGN OJOD +1E5D0..1E5ED ; XID_Start # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5F0 ; XID_Start # Lo OL ONAL SIGN HODDOND 1E7E0..1E7E6 ; XID_Start # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; XID_Start # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; XID_Start # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -8973,7 +9148,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 30000..3134A ; XID_Start # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A 31350..323AF ; XID_Start # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF -# Total code points: 136944 +# Total code points: 141246 # ================================================ @@ -9076,7 +9251,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 0860..086A ; XID_Continue # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 0870..0887 ; XID_Continue # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT 0889..088E ; XID_Continue # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL -0898..089F ; XID_Continue # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; XID_Continue # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08A0..08C8 ; XID_Continue # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; XID_Continue # Lm ARABIC SMALL FARSI YEH 08CA..08E1 ; XID_Continue # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA @@ -9509,7 +9684,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 1C50..1C59 ; XID_Continue # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE 1C5A..1C77 ; XID_Continue # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; XID_Continue # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD -1C80..1C88 ; XID_Continue # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; XID_Continue # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; XID_Continue # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; XID_Continue # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CD0..1CD2 ; XID_Continue # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA @@ -9652,10 +9827,10 @@ A771..A787 ; XID_Continue # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETT A788 ; XID_Continue # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; XID_Continue # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; XID_Continue # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; XID_Continue # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; XID_Continue # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; XID_Continue # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; XID_Continue # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; XID_Continue # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; XID_Continue # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; XID_Continue # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; XID_Continue # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; XID_Continue # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -9850,6 +10025,7 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 105A3..105B1 ; XID_Continue # L& [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; XID_Continue # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; XID_Continue # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; XID_Continue # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; XID_Continue # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; XID_Continue # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; XID_Continue # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -9894,10 +10070,19 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 10D00..10D23 ; XID_Continue # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA 10D24..10D27 ; XID_Continue # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI 10D30..10D39 ; XID_Continue # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +10D40..10D49 ; XID_Continue # Nd [10] GARAY DIGIT ZERO..GARAY DIGIT NINE +10D4A..10D4D ; XID_Continue # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; XID_Continue # Lm GARAY VOWEL LENGTH MARK +10D4F ; XID_Continue # Lo GARAY SUKUN +10D50..10D65 ; XID_Continue # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D69..10D6D ; XID_Continue # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK +10D6F ; XID_Continue # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; XID_Continue # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 10E80..10EA9 ; XID_Continue # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EAB..10EAC ; XID_Continue # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK 10EB0..10EB1 ; XID_Continue # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE -10EFD..10EFF ; XID_Continue # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EC2..10EC4 ; XID_Continue # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW +10EFC..10EFF ; XID_Continue # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F00..10F1C ; XID_Continue # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; XID_Continue # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; XID_Continue # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -9993,6 +10178,24 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 11362..11363 ; XID_Continue # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C ; XID_Continue # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; XID_Continue # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11380..11389 ; XID_Continue # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; XID_Continue # Lo TULU-TIGALARI LETTER EE +1138E ; XID_Continue # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; XID_Continue # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; XID_Continue # Lo TULU-TIGALARI SIGN AVAGRAHA +113B8..113BA ; XID_Continue # Mc [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II +113BB..113C0 ; XID_Continue # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113C2 ; XID_Continue # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; XID_Continue # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113CA ; XID_Continue # Mc [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; XID_Continue # Mc [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA +113CE ; XID_Continue # Mn TULU-TIGALARI SIGN VIRAMA +113CF ; XID_Continue # Mc TULU-TIGALARI SIGN LOOPED VIRAMA +113D0 ; XID_Continue # Mn TULU-TIGALARI CONJOINER +113D1 ; XID_Continue # Lo TULU-TIGALARI REPHA +113D2 ; XID_Continue # Mn TULU-TIGALARI GEMINATION MARK +113D3 ; XID_Continue # Lo TULU-TIGALARI SIGN PLUTA +113E1..113E2 ; XID_Continue # Mn [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11400..11434 ; XID_Continue # Lo [53] NEWA LETTER A..NEWA LETTER HA 11435..11437 ; XID_Continue # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11438..1143F ; XID_Continue # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI @@ -10044,8 +10247,11 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 116B7 ; XID_Continue # Mn TAKRI SIGN NUKTA 116B8 ; XID_Continue # Lo TAKRI LETTER ARCHAIC KHA 116C0..116C9 ; XID_Continue # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE +116D0..116E3 ; XID_Continue # Nd [20] MYANMAR PAO DIGIT ZERO..MYANMAR EASTERN PWO KAREN DIGIT NINE 11700..1171A ; XID_Continue # Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA -1171D..1171F ; XID_Continue # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; XID_Continue # Mn AHOM CONSONANT SIGN MEDIAL LA +1171E ; XID_Continue # Mc AHOM CONSONANT SIGN MEDIAL RA +1171F ; XID_Continue # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11720..11721 ; XID_Continue # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11722..11725 ; XID_Continue # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11726 ; XID_Continue # Mc AHOM VOWEL SIGN E @@ -10103,6 +10309,8 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 11A98..11A99 ; XID_Continue # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER 11A9D ; XID_Continue # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; XID_Continue # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; XID_Continue # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO +11BF0..11BF9 ; XID_Continue # Nd [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE 11C00..11C08 ; XID_Continue # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; XID_Continue # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C2F ; XID_Continue # Mc BHAIKSUKI VOWEL SIGN AA @@ -10156,6 +10364,7 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 11F41 ; XID_Continue # Mc KAWI SIGN KILLER 11F42 ; XID_Continue # Mn KAWI CONJOINER 11F50..11F59 ; XID_Continue # Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE +11F5A ; XID_Continue # Mn KAWI SIGN NUKTA 11FB0 ; XID_Continue # Lo LISU LETTER YHA 12000..12399 ; XID_Continue # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U 12400..1246E ; XID_Continue # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM @@ -10165,7 +10374,13 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 13440 ; XID_Continue # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13441..13446 ; XID_Continue # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN 13447..13455 ; XID_Continue # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +13460..143FA ; XID_Continue # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; XID_Continue # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; XID_Continue # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA +1611E..16129 ; XID_Continue # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612A..1612C ; XID_Continue # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA +1612D..1612F ; XID_Continue # Mn [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA +16130..16139 ; XID_Continue # Nd [10] GURUNG KHEMA DIGIT ZERO..GURUNG KHEMA DIGIT NINE 16800..16A38 ; XID_Continue # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; XID_Continue # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A60..16A69 ; XID_Continue # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE @@ -10179,6 +10394,10 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 16B50..16B59 ; XID_Continue # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE 16B63..16B77 ; XID_Continue # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; XID_Continue # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; XID_Continue # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; XID_Continue # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; XID_Continue # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT +16D70..16D79 ; XID_Continue # Nd [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE 16E40..16E7F ; XID_Continue # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16F00..16F4A ; XID_Continue # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F4F ; XID_Continue # Mn MIAO SIGN CONSONANT MODIFIER BAR @@ -10192,7 +10411,7 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 16FF0..16FF1 ; XID_Continue # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY 17000..187F7 ; XID_Continue # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; XID_Continue # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; XID_Continue # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; XID_Continue # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; XID_Continue # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; XID_Continue # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; XID_Continue # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -10207,6 +10426,7 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 1BC80..1BC88 ; XID_Continue # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL 1BC90..1BC99 ; XID_Continue # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW 1BC9D..1BC9E ; XID_Continue # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1CCF0..1CCF9 ; XID_Continue # Nd [10] OUTLINED DIGIT ZERO..OUTLINED DIGIT NINE 1CF00..1CF2D ; XID_Continue # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT 1CF30..1CF46 ; XID_Continue # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG 1D165..1D166 ; XID_Continue # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM @@ -10278,6 +10498,10 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 1E4EB ; XID_Continue # Lm NAG MUNDARI SIGN OJOD 1E4EC..1E4EF ; XID_Continue # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH 1E4F0..1E4F9 ; XID_Continue # Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE +1E5D0..1E5ED ; XID_Continue # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5EE..1E5EF ; XID_Continue # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR +1E5F0 ; XID_Continue # Lo OL ONAL SIGN HODDOND +1E5F1..1E5FA ; XID_Continue # Nd [10] OL ONAL DIGIT ZERO..OL ONAL DIGIT NINE 1E7E0..1E7E6 ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; XID_Continue # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; XID_Continue # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -10333,7 +10557,7 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 31350..323AF ; XID_Continue # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF E0100..E01EF ; XID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 140089 +# Total code points: 144522 # ================================================ @@ -10418,7 +10642,7 @@ E01F0..E0FFF ; Default_Ignorable_Code_Point # Cn [3600] ........ 086B..086F ; Cn # [5] .. 088F ; Cn # -0892..0897 ; Cn # [6] .. +0892..0896 ; Cn # [5] .. 0984 ; Cn # 098D..098E ; Cn # [2] .. 0991..0992 ; Cn # [2] .. @@ -229,12 +229,11 @@ 1A9A..1A9F ; Cn # [6] .. 1AAE..1AAF ; Cn # [2] .. 1ACF..1AFF ; Cn # [49] .. -1B4D..1B4F ; Cn # [3] .. -1B7F ; Cn # +1B4D ; Cn # 1BF4..1BFB ; Cn # [8] .. 1C38..1C3A ; Cn # [3] .. 1C4A..1C4C ; Cn # [3] .. -1C89..1C8F ; Cn # [7] .. +1C8B..1C8F ; Cn # [5] .. 1CBB..1CBC ; Cn # [2] .. 1CC8..1CCF ; Cn # [8] .. 1CFB..1CFF ; Cn # [5] .. @@ -261,7 +260,7 @@ 20C1..20CF ; Cn # [15] .. 20F1..20FF ; Cn # [15] .. 218C..218F ; Cn # [4] .. -2427..243F ; Cn # [25] .. +242A..243F ; Cn # [22] .. 244B..245F ; Cn # [21] .. 2B74..2B75 ; Cn # [2] .. 2B96 ; Cn # @@ -289,16 +288,16 @@ 3100..3104 ; Cn # [5] .. 3130 ; Cn # 318F ; Cn # -31E4..31EE ; Cn # [11] .. +31E6..31EE ; Cn # [9] .. 321F ; Cn # A48D..A48F ; Cn # [3] .. A4C7..A4CF ; Cn # [9] .. A62C..A63F ; Cn # [20] .. A6F8..A6FF ; Cn # [8] .. -A7CB..A7CF ; Cn # [5] .. +A7CE..A7CF ; Cn # [2] .. A7D2 ; Cn # A7D4 ; Cn # -A7DA..A7F1 ; Cn # [24] .. +A7DD..A7F1 ; Cn # [21] .. A82D..A82F ; Cn # [3] .. A83A..A83F ; Cn # [6] .. A878..A87F ; Cn # [8] .. @@ -388,7 +387,8 @@ FFFE..FFFF ; Cn # [2] .. 105A2 ; Cn # 105B2 ; Cn # 105BA ; Cn # -105BD..105FF ; Cn # [67] .. +105BD..105BF ; Cn # [3] .. +105F4..105FF ; Cn # [12] .. 10737..1073F ; Cn # [9] .. 10756..1075F ; Cn # [10] .. 10768..1077F ; Cn # [24] .. @@ -431,11 +431,15 @@ FFFE..FFFF ; Cn # [2] .. 10CB3..10CBF ; Cn # [13] .. 10CF3..10CF9 ; Cn # [7] .. 10D28..10D2F ; Cn # [8] .. -10D3A..10E5F ; Cn # [294] .. +10D3A..10D3F ; Cn # [6] .. +10D66..10D68 ; Cn # [3] .. +10D86..10D8D ; Cn # [8] .. +10D90..10E5F ; Cn # [208] .. 10E7F ; Cn # 10EAA ; Cn # 10EAE..10EAF ; Cn # [2] .. -10EB2..10EFC ; Cn # [75] .. +10EB2..10EC1 ; Cn # [16] .. +10EC5..10EFB ; Cn # [55] .. 10F28..10F2F ; Cn # [8] .. 10F5A..10F6F ; Cn # [22] .. 10F8A..10FAF ; Cn # [38] .. @@ -475,7 +479,18 @@ FFFE..FFFF ; Cn # [2] .. 11358..1135C ; Cn # [5] .. 11364..11365 ; Cn # [2] .. 1136D..1136F ; Cn # [3] .. -11375..113FF ; Cn # [139] .. +11375..1137F ; Cn # [11] .. +1138A ; Cn # +1138C..1138D ; Cn # [2] .. +1138F ; Cn # +113B6 ; Cn # +113C1 ; Cn # +113C3..113C4 ; Cn # [2] .. +113C6 ; Cn # +113CB ; Cn # +113D6 ; Cn # +113D9..113E0 ; Cn # [8] .. +113E3..113FF ; Cn # [29] .. 1145C ; Cn # 11462..1147F ; Cn # [30] .. 114C8..114CF ; Cn # [8] .. @@ -486,7 +501,8 @@ FFFE..FFFF ; Cn # [2] .. 1165A..1165F ; Cn # [6] .. 1166D..1167F ; Cn # [19] .. 116BA..116BF ; Cn # [6] .. -116CA..116FF ; Cn # [54] .. +116CA..116CF ; Cn # [6] .. +116E4..116FF ; Cn # [28] .. 1171B..1171C ; Cn # [2] .. 1172C..1172F ; Cn # [4] .. 11747..117FF ; Cn # [185] .. @@ -506,7 +522,9 @@ FFFE..FFFF ; Cn # [2] .. 11A48..11A4F ; Cn # [8] .. 11AA3..11AAF ; Cn # [13] .. 11AF9..11AFF ; Cn # [7] .. -11B0A..11BFF ; Cn # [246] .. +11B0A..11BBF ; Cn # [182] .. +11BE2..11BEF ; Cn # [14] .. +11BFA..11BFF ; Cn # [6] .. 11C09 ; Cn # 11C37 ; Cn # 11C46..11C4F ; Cn # [10] .. @@ -530,7 +548,7 @@ FFFE..FFFF ; Cn # [2] .. 11EF9..11EFF ; Cn # [7] .. 11F11 ; Cn # 11F3B..11F3D ; Cn # [3] .. -11F5A..11FAF ; Cn # [86] .. +11F5B..11FAF ; Cn # [85] .. 11FB1..11FBF ; Cn # [15] .. 11FF2..11FFE ; Cn # [13] .. 1239A..123FF ; Cn # [102] .. @@ -538,8 +556,10 @@ FFFE..FFFF ; Cn # [2] .. 12475..1247F ; Cn # [11] .. 12544..12F8F ; Cn # [2636] .. 12FF3..12FFF ; Cn # [13] .. -13456..143FF ; Cn # [4010] .. -14647..167FF ; Cn # [8633] .. +13456..1345F ; Cn # [10] .. +143FB..143FF ; Cn # [5] .. +14647..160FF ; Cn # [6841] .. +1613A..167FF ; Cn # [1734] .. 16A39..16A3F ; Cn # [7] .. 16A5F ; Cn # 16A6A..16A6D ; Cn # [4] .. @@ -551,7 +571,8 @@ FFFE..FFFF ; Cn # [2] .. 16B5A ; Cn # 16B62 ; Cn # 16B78..16B7C ; Cn # [5] .. -16B90..16E3F ; Cn # [688] .. +16B90..16D3F ; Cn # [432] .. +16D7A..16E3F ; Cn # [198] .. 16E9B..16EFF ; Cn # [101] .. 16F4B..16F4E ; Cn # [4] .. 16F88..16F8E ; Cn # [7] .. @@ -559,7 +580,7 @@ FFFE..FFFF ; Cn # [2] .. 16FE5..16FEF ; Cn # [11] .. 16FF2..16FFF ; Cn # [14] .. 187F8..187FF ; Cn # [8] .. -18CD6..18CFF ; Cn # [42] .. +18CD6..18CFE ; Cn # [41] .. 18D09..1AFEF ; Cn # [8935] .. 1AFF4 ; Cn # 1AFFC ; Cn # @@ -574,7 +595,9 @@ FFFE..FFFF ; Cn # [2] .. 1BC7D..1BC7F ; Cn # [3] .. 1BC89..1BC8F ; Cn # [7] .. 1BC9A..1BC9B ; Cn # [2] .. -1BCA4..1CEFF ; Cn # [4700] .. +1BCA4..1CBFF ; Cn # [3932] .. +1CCFA..1CCFF ; Cn # [6] .. +1CEB4..1CEFF ; Cn # [76] .. 1CF2E..1CF2F ; Cn # [2] .. 1CF47..1CF4F ; Cn # [9] .. 1CFC4..1CFFF ; Cn # [60] .. @@ -625,7 +648,9 @@ FFFE..FFFF ; Cn # [2] .. 1E2AF..1E2BF ; Cn # [17] .. 1E2FA..1E2FE ; Cn # [5] .. 1E300..1E4CF ; Cn # [464] .. -1E4FA..1E7DF ; Cn # [742] .. +1E4FA..1E5CF ; Cn # [214] .. +1E5FB..1E5FE ; Cn # [4] .. +1E600..1E7DF ; Cn # [480] .. 1E7E7 ; Cn # 1E7EC ; Cn # 1E7EF ; Cn # @@ -695,18 +720,17 @@ FFFE..FFFF ; Cn # [2] .. 1F85A..1F85F ; Cn # [6] .. 1F888..1F88F ; Cn # [8] .. 1F8AE..1F8AF ; Cn # [2] .. -1F8B2..1F8FF ; Cn # [78] .. +1F8BC..1F8BF ; Cn # [4] .. +1F8C2..1F8FF ; Cn # [62] .. 1FA54..1FA5F ; Cn # [12] .. 1FA6E..1FA6F ; Cn # [2] .. 1FA7D..1FA7F ; Cn # [3] .. -1FA89..1FA8F ; Cn # [7] .. -1FABE ; Cn # -1FAC6..1FACD ; Cn # [8] .. -1FADC..1FADF ; Cn # [4] .. -1FAE9..1FAEF ; Cn # [7] .. +1FA8A..1FA8E ; Cn # [5] .. +1FAC7..1FACD ; Cn # [7] .. +1FADD..1FADE ; Cn # [2] .. +1FAEA..1FAEF ; Cn # [6] .. 1FAF9..1FAFF ; Cn # [7] .. 1FB93 ; Cn # -1FBCB..1FBEF ; Cn # [37] .. 1FBFA..1FFFF ; Cn # [1030] .. 2A6E0..2A6FF ; Cn # [32] .. 2B73A..2B73F ; Cn # [6] .. @@ -723,7 +747,7 @@ E01F0..EFFFF ; Cn # [65040] .. FFFFE..FFFFF ; Cn # [2] .. 10FFFE..10FFFF; Cn # [2] .. -# Total code points: 824718 +# Total code points: 819533 # ================================================ @@ -1005,6 +1029,7 @@ FFFFE..FFFFF ; Cn # [2] .. 10C7 ; Lu # GEORGIAN CAPITAL LETTER YN 10CD ; Lu # GEORGIAN CAPITAL LETTER AEN 13A0..13F5 ; Lu # [86] CHEROKEE LETTER A..CHEROKEE LETTER MV +1C89 ; Lu # CYRILLIC CAPITAL LETTER TJE 1C90..1CBA ; Lu # [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Lu # [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1E00 ; Lu # LATIN CAPITAL LETTER A WITH RING BELOW @@ -1329,9 +1354,12 @@ A7C0 ; Lu # LATIN CAPITAL LETTER OLD POLISH O A7C2 ; Lu # LATIN CAPITAL LETTER ANGLICANA W A7C4..A7C7 ; Lu # [4] LATIN CAPITAL LETTER C WITH PALATAL HOOK..LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9 ; Lu # LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY +A7CB..A7CC ; Lu # [2] LATIN CAPITAL LETTER RAMS HORN..LATIN CAPITAL LETTER S WITH DIAGONAL STROKE A7D0 ; Lu # LATIN CAPITAL LETTER CLOSED INSULAR G A7D6 ; Lu # LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8 ; Lu # LATIN CAPITAL LETTER SIGMOID S +A7DA ; Lu # LATIN CAPITAL LETTER LAMBDA +A7DC ; Lu # LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F5 ; Lu # LATIN CAPITAL LETTER REVERSED HALF H FF21..FF3A ; Lu # [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z 10400..10427 ; Lu # [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW @@ -1341,6 +1369,7 @@ FF21..FF3A ; Lu # [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAP 1058C..10592 ; Lu # [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE 10594..10595 ; Lu # [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE 10C80..10CB2 ; Lu # [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10D50..10D65 ; Lu # [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA 118A0..118BF ; Lu # [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 16E40..16E5F ; Lu # [32] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN CAPITAL LETTER Y 1D400..1D419 ; Lu # [26] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL BOLD CAPITAL Z @@ -1376,7 +1405,7 @@ FF21..FF3A ; Lu # [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAP 1D7CA ; Lu # MATHEMATICAL BOLD CAPITAL DIGAMMA 1E900..1E921 ; Lu # [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA -# Total code points: 1831 +# Total code points: 1858 # ================================================ @@ -1656,6 +1685,7 @@ FF21..FF3A ; Lu # [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAP 10FD..10FF ; Ll # [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN 13F8..13FD ; Ll # [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV 1C80..1C88 ; Ll # [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C8A ; Ll # CYRILLIC SMALL LETTER TJE 1D00..1D2B ; Ll # [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL 1D6B..1D77 ; Ll # [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G 1D79..1D9A ; Ll # [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK @@ -1986,11 +2016,13 @@ A7C1 ; Ll # LATIN SMALL LETTER OLD POLISH O A7C3 ; Ll # LATIN SMALL LETTER ANGLICANA W A7C8 ; Ll # LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY A7CA ; Ll # LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7CD ; Ll # LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D1 ; Ll # LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; Ll # LATIN SMALL LETTER DOUBLE THORN A7D5 ; Ll # LATIN SMALL LETTER DOUBLE WYNN A7D7 ; Ll # LATIN SMALL LETTER MIDDLE SCOTS S A7D9 ; Ll # LATIN SMALL LETTER SIGMOID S +A7DB ; Ll # LATIN SMALL LETTER LAMBDA A7F6 ; Ll # LATIN SMALL LETTER REVERSED HALF H A7FA ; Ll # LATIN LETTER SMALL CAPITAL TURNED M AB30..AB5A ; Ll # [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG @@ -2006,6 +2038,7 @@ FF41..FF5A ; Ll # [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL 105B3..105B9 ; Ll # [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; Ll # [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE 10CC0..10CF2 ; Ll # [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D70..10D85 ; Ll # [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118C0..118DF ; Ll # [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E60..16E7F ; Ll # [32] MEDEFAIDRIN SMALL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1D41A..1D433 ; Ll # [26] MATHEMATICAL BOLD SMALL A..MATHEMATICAL BOLD SMALL Z @@ -2041,7 +2074,7 @@ FF41..FF5A ; Ll # [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL 1DF25..1DF2A ; Ll # [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK 1E922..1E943 ; Ll # [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 2233 +# Total code points: 2258 # ================================================ @@ -2124,7 +2157,11 @@ FF9E..FF9F ; Lm # [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAK 10780..10785 ; Lm # [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK 10787..107B0 ; Lm # [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK 107B2..107BA ; Lm # [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL +10D4E ; Lm # GARAY VOWEL LENGTH MARK +10D6F ; Lm # GARAY REDUPLICATION MARK 16B40..16B43 ; Lm # [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM +16D40..16D42 ; Lm # [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D6B..16D6C ; Lm # [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16F93..16F9F ; Lm # [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 16FE0..16FE1 ; Lm # [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK 16FE3 ; Lm # OLD CHINESE ITERATION MARK @@ -2136,7 +2173,7 @@ FF9E..FF9F ; Lm # [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAK 1E4EB ; Lm # NAG MUNDARI SIGN OJOD 1E94B ; Lm # ADLAM NASALIZATION MARK -# Total code points: 397 +# Total code points: 404 # ================================================ @@ -2451,6 +2488,7 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 10450..1049D ; Lo # [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO 10500..10527 ; Lo # [40] ELBASAN LETTER A..ELBASAN LETTER KHE 10530..10563 ; Lo # [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW +105C0..105F3 ; Lo # [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; Lo # [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; Lo # [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; Lo # [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -2482,8 +2520,11 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 10B80..10B91 ; Lo # [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW 10C00..10C48 ; Lo # [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH 10D00..10D23 ; Lo # [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA +10D4A..10D4D ; Lo # [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4F ; Lo # GARAY SUKUN 10E80..10EA9 ; Lo # [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EB0..10EB1 ; Lo # [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10EC2..10EC4 ; Lo # [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW 10F00..10F1C ; Lo # [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; Lo # OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; Lo # [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -2522,6 +2563,13 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 1133D ; Lo # GRANTHA SIGN AVAGRAHA 11350 ; Lo # GRANTHA OM 1135D..11361 ; Lo # [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11380..11389 ; Lo # [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; Lo # TULU-TIGALARI LETTER EE +1138E ; Lo # TULU-TIGALARI LETTER AI +11390..113B5 ; Lo # [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; Lo # TULU-TIGALARI SIGN AVAGRAHA +113D1 ; Lo # TULU-TIGALARI REPHA +113D3 ; Lo # TULU-TIGALARI SIGN PLUTA 11400..11434 ; Lo # [53] NEWA LETTER A..NEWA LETTER HA 11447..1144A ; Lo # [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI 1145F..11461 ; Lo # [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA @@ -2555,6 +2603,7 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 11A5C..11A89 ; Lo # [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA 11A9D ; Lo # SOYOMBO MARK PLUTA 11AB0..11AF8 ; Lo # [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; Lo # [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO 11C00..11C08 ; Lo # [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; Lo # [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C40 ; Lo # BHAIKSUKI SIGN AVAGRAHA @@ -2577,7 +2626,9 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 12F90..12FF0 ; Lo # [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 13000..1342F ; Lo # [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D 13441..13446 ; Lo # [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN +13460..143FA ; Lo # [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; Lo # [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; Lo # [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA 16800..16A38 ; Lo # [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; Lo # [31] MRO LETTER TA..MRO LETTER TEK 16A70..16ABE ; Lo # [79] TANGSA LETTER OZ..TANGSA LETTER ZA @@ -2585,11 +2636,12 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 16B00..16B2F ; Lo # [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU 16B63..16B77 ; Lo # [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; Lo # [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D43..16D6A ; Lo # [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU 16F00..16F4A ; Lo # [75] MIAO LETTER PA..MIAO LETTER RTE 16F50 ; Lo # MIAO LETTER NASALIZATION 17000..187F7 ; Lo # [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; Lo # [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; Lo # [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; Lo # [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1B000..1B122 ; Lo # [291] KATAKANA LETTER ARCHAIC E..KATAKANA LETTER ARCHAIC WU 1B132 ; Lo # HIRAGANA LETTER SMALL KO 1B150..1B152 ; Lo # [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO @@ -2606,6 +2658,8 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 1E290..1E2AD ; Lo # [30] TOTO LETTER PA..TOTO LETTER A 1E2C0..1E2EB ; Lo # [44] WANCHO LETTER AA..WANCHO LETTER YIH 1E4D0..1E4EA ; Lo # [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL +1E5D0..1E5ED ; Lo # [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5F0 ; Lo # OL ONAL SIGN HODDOND 1E7E0..1E7E6 ; Lo # [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; Lo # [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; Lo # [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -2654,7 +2708,7 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 30000..3134A ; Lo # [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A 31350..323AF ; Lo # [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF -# Total code points: 132234 +# Total code points: 136477 # ================================================ @@ -2684,7 +2738,7 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 0825..0827 ; Mn # [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082D ; Mn # [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA 0859..085B ; Mn # [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK -0898..089F ; Mn # [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; Mn # [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08CA..08E1 ; Mn # [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA 08E3..0902 ; Mn # [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA 093A ; Mn # DEVANAGARI VOWEL SIGN OE @@ -2882,8 +2936,9 @@ FE20..FE2F ; Mn # [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITL 10A3F ; Mn # KHAROSHTHI VIRAMA 10AE5..10AE6 ; Mn # [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW 10D24..10D27 ; Mn # [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D69..10D6D ; Mn # [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK 10EAB..10EAC ; Mn # [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK -10EFD..10EFF ; Mn # [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EFC..10EFF ; Mn # [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F46..10F50 ; Mn # [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW 10F82..10F85 ; Mn # [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW 11001 ; Mn # BRAHMI SIGN ANUSVARA @@ -2914,6 +2969,11 @@ FE20..FE2F ; Mn # [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITL 11340 ; Mn # GRANTHA VOWEL SIGN II 11366..1136C ; Mn # [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; Mn # [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +113BB..113C0 ; Mn # [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113CE ; Mn # TULU-TIGALARI SIGN VIRAMA +113D0 ; Mn # TULU-TIGALARI CONJOINER +113D2 ; Mn # TULU-TIGALARI GEMINATION MARK +113E1..113E2 ; Mn # [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11438..1143F ; Mn # [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI 11442..11444 ; Mn # [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA 11446 ; Mn # NEWA SIGN NUKTA @@ -2933,7 +2993,8 @@ FE20..FE2F ; Mn # [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITL 116AD ; Mn # TAKRI VOWEL SIGN AA 116B0..116B5 ; Mn # [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU 116B7 ; Mn # TAKRI SIGN NUKTA -1171D..1171F ; Mn # [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; Mn # AHOM CONSONANT SIGN MEDIAL LA +1171F ; Mn # AHOM CONSONANT SIGN MEDIAL LIGATING RA 11722..11725 ; Mn # [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11727..1172B ; Mn # [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER 1182F..11837 ; Mn # [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA @@ -2972,8 +3033,11 @@ FE20..FE2F ; Mn # [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITL 11F36..11F3A ; Mn # [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R 11F40 ; Mn # KAWI VOWEL SIGN EU 11F42 ; Mn # KAWI CONJOINER +11F5A ; Mn # KAWI SIGN NUKTA 13440 ; Mn # EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13447..13455 ; Mn # [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +1611E..16129 ; Mn # [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612D..1612F ; Mn # [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA 16AF0..16AF4 ; Mn # [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; Mn # [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F4F ; Mn # MIAO SIGN CONSONANT MODIFIER BAR @@ -3003,11 +3067,12 @@ FE20..FE2F ; Mn # [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITL 1E2AE ; Mn # TOTO SIGN RISING TONE 1E2EC..1E2EF ; Mn # [4] WANCHO TONE TUP..WANCHO TONE KOINI 1E4EC..1E4EF ; Mn # [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH +1E5EE..1E5EF ; Mn # [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR 1E8D0..1E8D6 ; Mn # [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS 1E944..1E94A ; Mn # [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA E0100..E01EF ; Mn # [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 1985 +# Total code points: 2020 # ================================================ @@ -3159,6 +3224,12 @@ ABEC ; Mc # MEETEI MAYEK LUM IYEK 1134B..1134D ; Mc # [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA 11357 ; Mc # GRANTHA AU LENGTH MARK 11362..11363 ; Mc # [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +113B8..113BA ; Mc # [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II +113C2 ; Mc # TULU-TIGALARI VOWEL SIGN EE +113C5 ; Mc # TULU-TIGALARI VOWEL SIGN AI +113C7..113CA ; Mc # [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; Mc # [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA +113CF ; Mc # TULU-TIGALARI SIGN LOOPED VIRAMA 11435..11437 ; Mc # [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11440..11441 ; Mc # [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU 11445 ; Mc # NEWA SIGN VISARGA @@ -3175,6 +3246,7 @@ ABEC ; Mc # MEETEI MAYEK LUM IYEK 116AC ; Mc # TAKRI SIGN VISARGA 116AE..116AF ; Mc # [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II 116B6 ; Mc # TAKRI SIGN VIRAMA +1171E ; Mc # AHOM CONSONANT SIGN MEDIAL RA 11720..11721 ; Mc # [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11726 ; Mc # AHOM VOWEL SIGN E 1182C..1182E ; Mc # [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II @@ -3203,12 +3275,13 @@ ABEC ; Mc # MEETEI MAYEK LUM IYEK 11F34..11F35 ; Mc # [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA 11F3E..11F3F ; Mc # [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI 11F41 ; Mc # KAWI SIGN KILLER +1612A..1612C ; Mc # [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA 16F51..16F87 ; Mc # [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI 16FF0..16FF1 ; Mc # [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY 1D165..1D166 ; Mc # [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM 1D16D..1D172 ; Mc # [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 -# Total code points: 452 +# Total code points: 468 # ================================================ @@ -3253,6 +3326,7 @@ ABF0..ABF9 ; Nd # [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE FF10..FF19 ; Nd # [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE 104A0..104A9 ; Nd # [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE 10D30..10D39 ; Nd # [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +10D40..10D49 ; Nd # [10] GARAY DIGIT ZERO..GARAY DIGIT NINE 11066..1106F ; Nd # [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE 110F0..110F9 ; Nd # [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE 11136..1113F ; Nd # [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE @@ -3262,24 +3336,30 @@ FF10..FF19 ; Nd # [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE 114D0..114D9 ; Nd # [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE 11650..11659 ; Nd # [10] MODI DIGIT ZERO..MODI DIGIT NINE 116C0..116C9 ; Nd # [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE +116D0..116E3 ; Nd # [20] MYANMAR PAO DIGIT ZERO..MYANMAR EASTERN PWO KAREN DIGIT NINE 11730..11739 ; Nd # [10] AHOM DIGIT ZERO..AHOM DIGIT NINE 118E0..118E9 ; Nd # [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE 11950..11959 ; Nd # [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE +11BF0..11BF9 ; Nd # [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE 11C50..11C59 ; Nd # [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE 11D50..11D59 ; Nd # [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE 11DA0..11DA9 ; Nd # [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE 11F50..11F59 ; Nd # [10] KAWI DIGIT ZERO..KAWI DIGIT NINE +16130..16139 ; Nd # [10] GURUNG KHEMA DIGIT ZERO..GURUNG KHEMA DIGIT NINE 16A60..16A69 ; Nd # [10] MRO DIGIT ZERO..MRO DIGIT NINE 16AC0..16AC9 ; Nd # [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE 16B50..16B59 ; Nd # [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE +16D70..16D79 ; Nd # [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE +1CCF0..1CCF9 ; Nd # [10] OUTLINED DIGIT ZERO..OUTLINED DIGIT NINE 1D7CE..1D7FF ; Nd # [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE 1E140..1E149 ; Nd # [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE 1E2F0..1E2F9 ; Nd # [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE 1E4F0..1E4F9 ; Nd # [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE +1E5F1..1E5FA ; Nd # [10] OL ONAL DIGIT ZERO..OL ONAL DIGIT NINE 1E950..1E959 ; Nd # [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE 1FBF0..1FBF9 ; Nd # [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE -# Total code points: 680 +# Total code points: 760 # ================================================ @@ -3486,9 +3566,10 @@ FE31..FE32 ; Pd # [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FE58 ; Pd # SMALL EM DASH FE63 ; Pd # SMALL HYPHEN-MINUS FF0D ; Pd # FULLWIDTH HYPHEN-MINUS +10D6E ; Pd # GARAY HYPHEN 10EAD ; Pd # YEZIDI HYPHENATION MARK -# Total code points: 26 +# Total code points: 27 # ================================================ @@ -3735,8 +3816,9 @@ FF3F ; Pc # FULLWIDTH LOW LINE 1A1E..1A1F ; Po # [2] BUGINESE PALLAWA..BUGINESE END OF SECTION 1AA0..1AA6 ; Po # [7] TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA 1AA8..1AAD ; Po # [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG +1B4E..1B4F ; Po # [2] BALINESE INVERTED CARIK SIKI..BALINESE INVERTED CARIK PAREREN 1B5A..1B60 ; Po # [7] BALINESE PANTI..BALINESE PAMENENG -1B7D..1B7E ; Po # [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG +1B7D..1B7F ; Po # [3] BALINESE PANTI LANTANG..BALINESE PANTI BAWAK 1BFC..1BFF ; Po # [4] BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT 1C3B..1C3F ; Po # [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK 1C7E..1C7F ; Po # [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD @@ -3831,6 +3913,8 @@ FF64..FF65 ; Po # [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDL 111DD..111DF ; Po # [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2 11238..1123D ; Po # [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN 112A9 ; Po # MULTANI SECTION MARK +113D4..113D5 ; Po # [2] TULU-TIGALARI DANDA..TULU-TIGALARI DOUBLE DANDA +113D7..113D8 ; Po # [2] TULU-TIGALARI SIGN OM PUSHPIKA..TULU-TIGALARI SIGN SHRII PUSHPIKA 1144B..1144F ; Po # [5] NEWA DANDA..NEWA ABBREVIATION SIGN 1145A..1145B ; Po # [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK 1145D ; Po # NEWA INSERTION SIGN @@ -3847,6 +3931,7 @@ FF64..FF65 ; Po # [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDL 11A9A..11A9C ; Po # [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD 11A9E..11AA2 ; Po # [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2 11B00..11B09 ; Po # [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU +11BE1 ; Po # SUNUWAR SIGN PVO 11C41..11C45 ; Po # [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2 11C70..11C71 ; Po # [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD 11EF7..11EF8 ; Po # [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION @@ -3858,13 +3943,15 @@ FF64..FF65 ; Po # [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDL 16AF5 ; Po # BASSA VAH FULL STOP 16B37..16B3B ; Po # [5] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS FEEM 16B44 ; Po # PAHAWH HMONG SIGN XAUS +16D6D..16D6F ; Po # [3] KIRAT RAI SIGN YUPI..KIRAT RAI DOUBLE DANDA 16E97..16E9A ; Po # [4] MEDEFAIDRIN COMMA..MEDEFAIDRIN EXCLAMATION OH 16FE2 ; Po # OLD CHINESE HOOK MARK 1BC9F ; Po # DUPLOYAN PUNCTUATION CHINOOK FULL STOP 1DA87..1DA8B ; Po # [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS +1E5FF ; Po # OL ONAL ABBREVIATION SIGN 1E95E..1E95F ; Po # [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK -# Total code points: 628 +# Total code points: 640 # ================================================ @@ -3923,6 +4010,7 @@ FF5C ; Sm # FULLWIDTH VERTICAL LINE FF5E ; Sm # FULLWIDTH TILDE FFE2 ; Sm # FULLWIDTH NOT SIGN FFE9..FFEC ; Sm # [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW +10D8E..10D8F ; Sm # [2] GARAY PLUS SIGN..GARAY MINUS SIGN 1D6C1 ; Sm # MATHEMATICAL BOLD NABLA 1D6DB ; Sm # MATHEMATICAL BOLD PARTIAL DIFFERENTIAL 1D6FB ; Sm # MATHEMATICAL ITALIC NABLA @@ -3935,7 +4023,7 @@ FFE9..FFEC ; Sm # [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW 1D7C3 ; Sm # MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL 1EEF0..1EEF1 ; Sm # [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL -# Total code points: 948 +# Total code points: 950 # ================================================ @@ -4073,7 +4161,7 @@ FFE3 ; Sk # FULLWIDTH MACRON 232B..237B ; So # [81] ERASE TO THE LEFT..NOT CHECK MARK 237D..239A ; So # [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL 23B4..23DB ; So # [40] TOP SQUARE BRACKET..FUSE -23E2..2426 ; So # [69] WHITE TRAPEZIUM..SYMBOL FOR SUBSTITUTE FORM TWO +23E2..2429 ; So # [72] WHITE TRAPEZIUM..SYMBOL FOR DELETE MEDIUM SHADE FORM 2440..244A ; So # [11] OCR HOOK..OCR DOUBLE BACKSLASH 249C..24E9 ; So # [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z 2500..25B6 ; So # [183] BOX DRAWINGS LIGHT HORIZONTAL..BLACK RIGHT-POINTING TRIANGLE @@ -4101,7 +4189,7 @@ FFE3 ; Sk # FULLWIDTH MACRON 303E..303F ; So # [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE 3190..3191 ; So # [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK 3196..319F ; So # [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK -31C0..31E3 ; So # [36] CJK STROKE T..CJK STROKE Q +31C0..31E5 ; So # [38] CJK STROKE T..CJK STROKE SZP 31EF ; So # IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION 3200..321E ; So # [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU 322A..3247 ; So # [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO @@ -4136,6 +4224,8 @@ FFFC..FFFD ; So # [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTER 16B3C..16B3F ; So # [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB 16B45 ; So # PAHAWH HMONG SIGN CIM TSOV ROG 1BC9C ; So # DUPLOYAN SIGN O WITH CROSS +1CC00..1CCEF ; So # [240] UP-POINTING GO-KART..OUTLINED LATIN CAPITAL LETTER Z +1CD00..1CEB3 ; So # [436] BLOCK OCTANT-3..BLACK RIGHT TRIANGLE CARET 1CF50..1CFC3 ; So # [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK 1D000..1D0F5 ; So # [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO 1D100..1D126 ; So # [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2 @@ -4180,20 +4270,20 @@ FFFC..FFFD ; So # [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTER 1F850..1F859 ; So # [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW 1F860..1F887 ; So # [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW 1F890..1F8AD ; So # [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS -1F8B0..1F8B1 ; So # [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST +1F8B0..1F8BB ; So # [12] ARROW POINTING UPWARDS THEN NORTH WEST..SOUTH WEST ARROW FROM BAR +1F8C0..1F8C1 ; So # [2] LEFTWARDS ARROW FROM DOWNWARDS ARROW..RIGHTWARDS ARROW FROM DOWNWARDS ARROW 1F900..1FA53 ; So # [340] CIRCLED CROSS FORMEE WITH FOUR DOTS..BLACK CHESS KNIGHT-BISHOP 1FA60..1FA6D ; So # [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER 1FA70..1FA7C ; So # [13] BALLET SHOES..CRUTCH -1FA80..1FA88 ; So # [9] YO-YO..FLUTE -1FA90..1FABD ; So # [46] RINGED PLANET..WING -1FABF..1FAC5 ; So # [7] GOOSE..PERSON WITH CROWN -1FACE..1FADB ; So # [14] MOOSE..PEA POD -1FAE0..1FAE8 ; So # [9] MELTING FACE..SHAKING FACE +1FA80..1FA89 ; So # [10] YO-YO..HARP +1FA8F..1FAC6 ; So # [56] SHOVEL..FINGERPRINT +1FACE..1FADC ; So # [15] MOOSE..ROOT VEGETABLE +1FADF..1FAE9 ; So # [11] SPLATTER..FACE WITH BAGS UNDER EYES 1FAF0..1FAF8 ; So # [9] HAND WITH INDEX FINGER AND THUMB CROSSED..RIGHTWARDS PUSHING HAND 1FB00..1FB92 ; So # [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK -1FB94..1FBCA ; So # [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON +1FB94..1FBEF ; So # [92] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..TOP LEFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLE -# Total code points: 6639 +# Total code points: 7376 # ================================================ diff --git a/libcxx/utils/data/unicode/EastAsianWidth.txt b/libcxx/utils/data/unicode/EastAsianWidth.txt index 02df4df475cbee..99f7a31ea5d8a2 100644 --- a/libcxx/utils/data/unicode/EastAsianWidth.txt +++ b/libcxx/utils/data/unicode/EastAsianWidth.txt @@ -1,8 +1,8 @@ -# EastAsianWidth-15.1.0.txt -# Date: 2023-07-28, 23:34:08 GMT -# © 2023 Unicode®, Inc. +# EastAsianWidth-16.0.0.txt +# Date: 2024-04-30, 21:48:20 GMT +# © 2024 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database # For documentation, see https://www.unicode.org/reports/tr44/ @@ -334,7 +334,7 @@ 0888 ; N # Sk ARABIC RAISED ROUND DOT 0889..088E ; N # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL 0890..0891 ; N # Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE -0898..089F ; N # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; N # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08A0..08C8 ; N # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; N # Lm ARABIC SMALL FARSI YEH 08CA..08E1 ; N # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA @@ -819,12 +819,13 @@ 1B42 ; N # Mn BALINESE VOWEL SIGN PEPET 1B43..1B44 ; N # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG 1B45..1B4C ; N # Lo [8] BALINESE LETTER KAF SASAK..BALINESE LETTER ARCHAIC JNYA +1B4E..1B4F ; N # Po [2] BALINESE INVERTED CARIK SIKI..BALINESE INVERTED CARIK PAREREN 1B50..1B59 ; N # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE 1B5A..1B60 ; N # Po [7] BALINESE PANTI..BALINESE PAMENENG 1B61..1B6A ; N # So [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE 1B6B..1B73 ; N # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG 1B74..1B7C ; N # So [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING -1B7D..1B7E ; N # Po [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG +1B7D..1B7F ; N # Po [3] BALINESE PANTI LANTANG..BALINESE PANTI BAWAK 1B80..1B81 ; N # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR 1B82 ; N # Mc SUNDANESE SIGN PANGWISAD 1B83..1BA0 ; N # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA @@ -859,7 +860,7 @@ 1C5A..1C77 ; N # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; N # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD 1C7E..1C7F ; N # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD -1C80..1C88 ; N # Ll [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; N # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; N # Lu [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; N # Lu [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CC0..1CC7 ; N # Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA @@ -1142,7 +1143,7 @@ 23F1..23F2 ; N # So [2] STOPWATCH..TIMER CLOCK 23F3 ; W # So HOURGLASS WITH FLOWING SAND 23F4..23FF ; N # So [12] BLACK MEDIUM LEFT-POINTING TRIANGLE..OBSERVER EYE SYMBOL -2400..2426 ; N # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO +2400..2429 ; N # So [42] SYMBOL FOR NULL..SYMBOL FOR DELETE MEDIUM SHADE FORM 2440..244A ; N # So [11] OCR HOOK..OCR DOUBLE BACKSLASH 2460..249B ; A # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP 249C..24E9 ; A # So [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z @@ -1195,7 +1196,9 @@ 261C ; A # So WHITE LEFT POINTING INDEX 261D ; N # So WHITE UP POINTING INDEX 261E ; A # So WHITE RIGHT POINTING INDEX -261F..263F ; N # So [33] WHITE DOWN POINTING INDEX..MERCURY +261F..262F ; N # So [17] WHITE DOWN POINTING INDEX..YIN YANG +2630..2637 ; W # So [8] TRIGRAM FOR HEAVEN..TRIGRAM FOR EARTH +2638..263F ; N # So [8] WHEEL OF DHARMA..MERCURY 2640 ; A # So FEMALE SIGN 2641 ; N # So EARTH 2642 ; A # So MALE SIGN @@ -1213,7 +1216,9 @@ 266F ; A # Sm MUSIC SHARP SIGN 2670..267E ; N # So [15] WEST SYRIAC CROSS..PERMANENT PAPER SIGN 267F ; W # So WHEELCHAIR SYMBOL -2680..2692 ; N # So [19] DIE FACE-1..HAMMER AND PICK +2680..2689 ; N # So [10] DIE FACE-1..BLACK CIRCLE WITH TWO WHITE DOTS +268A..268F ; W # So [6] MONOGRAM FOR YANG..DIGRAM FOR GREATER YIN +2690..2692 ; N # So [3] WHITE FLAG..HAMMER AND PICK 2693 ; W # So ANCHOR 2694..269D ; N # So [10] CROSSED SWORDS..OUTLINED WHITE STAR 269E..269F ; A # So [2] THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT @@ -1487,7 +1492,7 @@ 3192..3195 ; W # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK 3196..319F ; W # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK 31A0..31BF ; W # Lo [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH -31C0..31E3 ; W # So [36] CJK STROKE T..CJK STROKE Q +31C0..31E5 ; W # So [38] CJK STROKE T..CJK STROKE SZP 31EF ; W # So IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION 31F0..31FF ; W # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO 3200..321E ; W # So [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU @@ -1503,7 +1508,7 @@ 32C0..32FF ; W # So [64] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..SQUARE ERA NAME REIWA 3300..33FF ; W # So [256] SQUARE APAATO..SQUARE GAL 3400..4DBF ; W # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF -4DC0..4DFF ; N # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION +4DC0..4DFF ; W # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION 4E00..9FFF ; W # Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF A000..A014 ; W # Lo [21] YI SYLLABLE IT..YI SYLLABLE E A015 ; W # Lm YI SYLLABLE WU @@ -1543,10 +1548,10 @@ A788 ; N # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A789..A78A ; N # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN A78B..A78E ; N # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; N # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; N # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; N # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; N # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; N # Ll LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; N # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; N # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; N # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; N # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; N # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -1870,6 +1875,7 @@ FFFD ; A # So REPLACEMENT CHARACTER 105A3..105B1 ; N # Ll [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; N # Ll [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; N # Ll [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; N # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; N # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; N # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; N # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -1942,12 +1948,23 @@ FFFD ; A # So REPLACEMENT CHARACTER 10D00..10D23 ; N # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA 10D24..10D27 ; N # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI 10D30..10D39 ; N # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +10D40..10D49 ; N # Nd [10] GARAY DIGIT ZERO..GARAY DIGIT NINE +10D4A..10D4D ; N # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; N # Lm GARAY VOWEL LENGTH MARK +10D4F ; N # Lo GARAY SUKUN +10D50..10D65 ; N # Lu [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D69..10D6D ; N # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK +10D6E ; N # Pd GARAY HYPHEN +10D6F ; N # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; N # Ll [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA +10D8E..10D8F ; N # Sm [2] GARAY PLUS SIGN..GARAY MINUS SIGN 10E60..10E7E ; N # No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS 10E80..10EA9 ; N # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EAB..10EAC ; N # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK 10EAD ; N # Pd YEZIDI HYPHENATION MARK 10EB0..10EB1 ; N # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE -10EFD..10EFF ; N # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EC2..10EC4 ; N # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW +10EFC..10EFF ; N # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F00..10F1C ; N # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F1D..10F26 ; N # No [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF 10F27 ; N # Lo OLD SOGDIAN LIGATURE AYIN-DALETH @@ -2064,6 +2081,26 @@ FFFD ; A # So REPLACEMENT CHARACTER 11362..11363 ; N # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C ; N # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; N # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11380..11389 ; N # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; N # Lo TULU-TIGALARI LETTER EE +1138E ; N # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; N # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; N # Lo TULU-TIGALARI SIGN AVAGRAHA +113B8..113BA ; N # Mc [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II +113BB..113C0 ; N # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113C2 ; N # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; N # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113CA ; N # Mc [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; N # Mc [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA +113CE ; N # Mn TULU-TIGALARI SIGN VIRAMA +113CF ; N # Mc TULU-TIGALARI SIGN LOOPED VIRAMA +113D0 ; N # Mn TULU-TIGALARI CONJOINER +113D1 ; N # Lo TULU-TIGALARI REPHA +113D2 ; N # Mn TULU-TIGALARI GEMINATION MARK +113D3 ; N # Lo TULU-TIGALARI SIGN PLUTA +113D4..113D5 ; N # Po [2] TULU-TIGALARI DANDA..TULU-TIGALARI DOUBLE DANDA +113D7..113D8 ; N # Po [2] TULU-TIGALARI SIGN OM PUSHPIKA..TULU-TIGALARI SIGN SHRII PUSHPIKA +113E1..113E2 ; N # Mn [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11400..11434 ; N # Lo [53] NEWA LETTER A..NEWA LETTER HA 11435..11437 ; N # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11438..1143F ; N # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI @@ -2123,8 +2160,11 @@ FFFD ; A # So REPLACEMENT CHARACTER 116B8 ; N # Lo TAKRI LETTER ARCHAIC KHA 116B9 ; N # Po TAKRI ABBREVIATION SIGN 116C0..116C9 ; N # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE +116D0..116E3 ; N # Nd [20] MYANMAR PAO DIGIT ZERO..MYANMAR EASTERN PWO KAREN DIGIT NINE 11700..1171A ; N # Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA -1171D..1171F ; N # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; N # Mn AHOM CONSONANT SIGN MEDIAL LA +1171E ; N # Mc AHOM CONSONANT SIGN MEDIAL RA +1171F ; N # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11720..11721 ; N # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11722..11725 ; N # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11726 ; N # Mc AHOM VOWEL SIGN E @@ -2195,6 +2235,9 @@ FFFD ; A # So REPLACEMENT CHARACTER 11AB0..11ABF ; N # Lo [16] CANADIAN SYLLABICS NATTILIK HI..CANADIAN SYLLABICS SPA 11AC0..11AF8 ; N # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL 11B00..11B09 ; N # Po [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU +11BC0..11BE0 ; N # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO +11BE1 ; N # Po SUNUWAR SIGN PVO +11BF0..11BF9 ; N # Nd [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE 11C00..11C08 ; N # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; N # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C2F ; N # Mc BHAIKSUKI VOWEL SIGN AA @@ -2253,6 +2296,7 @@ FFFD ; A # So REPLACEMENT CHARACTER 11F42 ; N # Mn KAWI CONJOINER 11F43..11F4F ; N # Po [13] KAWI DANDA..KAWI PUNCTUATION CLOSING SPIRAL 11F50..11F59 ; N # Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE +11F5A ; N # Mn KAWI SIGN NUKTA 11FB0 ; N # Lo LISU LETTER YHA 11FC0..11FD4 ; N # No [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH 11FD5..11FDC ; N # So [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI @@ -2270,7 +2314,13 @@ FFFD ; A # So REPLACEMENT CHARACTER 13440 ; N # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13441..13446 ; N # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN 13447..13455 ; N # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +13460..143FA ; N # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; N # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; N # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA +1611E..16129 ; N # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612A..1612C ; N # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA +1612D..1612F ; N # Mn [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA +16130..16139 ; N # Nd [10] GURUNG KHEMA DIGIT ZERO..GURUNG KHEMA DIGIT NINE 16800..16A38 ; N # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; N # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A60..16A69 ; N # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE @@ -2291,6 +2341,11 @@ FFFD ; A # So REPLACEMENT CHARACTER 16B5B..16B61 ; N # No [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS 16B63..16B77 ; N # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; N # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; N # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; N # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; N # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT +16D6D..16D6F ; N # Po [3] KIRAT RAI SIGN YUPI..KIRAT RAI DOUBLE DANDA +16D70..16D79 ; N # Nd [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE 16E40..16E7F ; N # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16E80..16E96 ; N # No [23] MEDEFAIDRIN DIGIT ZERO..MEDEFAIDRIN DIGIT THREE ALTERNATE FORM 16E97..16E9A ; N # Po [4] MEDEFAIDRIN COMMA..MEDEFAIDRIN EXCLAMATION OH @@ -2308,6 +2363,7 @@ FFFD ; A # So REPLACEMENT CHARACTER 17000..187F7 ; W # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18AFF ; W # Lo [768] TANGUT COMPONENT-001..TANGUT COMPONENT-768 18B00..18CD5 ; W # Lo [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5 +18CFF ; W # Lo KHITAN SMALL SCRIPT CHARACTER-18CFF 18D00..18D08 ; W # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; W # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; W # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 @@ -2327,6 +2383,9 @@ FFFD ; A # So REPLACEMENT CHARACTER 1BC9D..1BC9E ; N # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK 1BC9F ; N # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP 1BCA0..1BCA3 ; N # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP +1CC00..1CCEF ; N # So [240] UP-POINTING GO-KART..OUTLINED LATIN CAPITAL LETTER Z +1CCF0..1CCF9 ; N # Nd [10] OUTLINED DIGIT ZERO..OUTLINED DIGIT NINE +1CD00..1CEB3 ; N # So [436] BLOCK OCTANT-3..BLACK RIGHT TRIANGLE CARET 1CF00..1CF2D ; N # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT 1CF30..1CF46 ; N # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG 1CF50..1CFC3 ; N # So [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK @@ -2349,8 +2408,9 @@ FFFD ; A # So REPLACEMENT CHARACTER 1D245 ; N # So GREEK MUSICAL LEIMMA 1D2C0..1D2D3 ; N # No [20] KAKTOVIK NUMERAL ZERO..KAKTOVIK NUMERAL NINETEEN 1D2E0..1D2F3 ; N # No [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN -1D300..1D356 ; N # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING -1D360..1D378 ; N # No [25] COUNTING ROD UNIT DIGIT ONE..TALLY MARK FIVE +1D300..1D356 ; W # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING +1D360..1D376 ; W # No [23] COUNTING ROD UNIT DIGIT ONE..IDEOGRAPHIC TALLY MARK FIVE +1D377..1D378 ; N # No [2] TALLY MARK ONE..TALLY MARK FIVE 1D400..1D454 ; N # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G 1D456..1D49C ; N # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A 1D49E..1D49F ; N # Lu [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D @@ -2431,6 +2491,11 @@ FFFD ; A # So REPLACEMENT CHARACTER 1E4EB ; N # Lm NAG MUNDARI SIGN OJOD 1E4EC..1E4EF ; N # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH 1E4F0..1E4F9 ; N # Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE +1E5D0..1E5ED ; N # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5EE..1E5EF ; N # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR +1E5F0 ; N # Lo OL ONAL SIGN HODDOND +1E5F1..1E5FA ; N # Nd [10] OL ONAL DIGIT ZERO..OL ONAL DIGIT NINE +1E5FF ; N # Po OL ONAL ABBREVIATION SIGN 1E7E0..1E7E6 ; N # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; N # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; N # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -2574,7 +2639,8 @@ FFFD ; A # So REPLACEMENT CHARACTER 1F850..1F859 ; N # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW 1F860..1F887 ; N # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW 1F890..1F8AD ; N # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS -1F8B0..1F8B1 ; N # So [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST +1F8B0..1F8BB ; N # So [12] ARROW POINTING UPWARDS THEN NORTH WEST..SOUTH WEST ARROW FROM BAR +1F8C0..1F8C1 ; N # So [2] LEFTWARDS ARROW FROM DOWNWARDS ARROW..RIGHTWARDS ARROW FROM DOWNWARDS ARROW 1F900..1F90B ; N # So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT 1F90C..1F93A ; W # So [47] PINCHED FINGERS..FENCER 1F93B ; N # So MODERN PENTATHLON @@ -2584,14 +2650,13 @@ FFFD ; A # So REPLACEMENT CHARACTER 1FA00..1FA53 ; N # So [84] NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP 1FA60..1FA6D ; N # So [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER 1FA70..1FA7C ; W # So [13] BALLET SHOES..CRUTCH -1FA80..1FA88 ; W # So [9] YO-YO..FLUTE -1FA90..1FABD ; W # So [46] RINGED PLANET..WING -1FABF..1FAC5 ; W # So [7] GOOSE..PERSON WITH CROWN -1FACE..1FADB ; W # So [14] MOOSE..PEA POD -1FAE0..1FAE8 ; W # So [9] MELTING FACE..SHAKING FACE +1FA80..1FA89 ; W # So [10] YO-YO..HARP +1FA8F..1FAC6 ; W # So [56] SHOVEL..FINGERPRINT +1FACE..1FADC ; W # So [15] MOOSE..ROOT VEGETABLE +1FADF..1FAE9 ; W # So [11] SPLATTER..FACE WITH BAGS UNDER EYES 1FAF0..1FAF8 ; W # So [9] HAND WITH INDEX FINGER AND THUMB CROSSED..RIGHTWARDS PUSHING HAND 1FB00..1FB92 ; N # So [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK -1FB94..1FBCA ; N # So [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON +1FB94..1FBEF ; N # So [92] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..TOP LEFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLE 1FBF0..1FBF9 ; N # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE 20000..2A6DF ; W # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF 2A6E0..2A6FF ; W # Cn [32] .. diff --git a/libcxx/utils/data/unicode/GraphemeBreakProperty.txt b/libcxx/utils/data/unicode/GraphemeBreakProperty.txt index 12453cbdb54a15..a863397ddabafe 100644 --- a/libcxx/utils/data/unicode/GraphemeBreakProperty.txt +++ b/libcxx/utils/data/unicode/GraphemeBreakProperty.txt @@ -1,8 +1,8 @@ -# GraphemeBreakProperty-15.1.0.txt -# Date: 2023-01-05, 20:34:41 GMT -# © 2023 Unicode®, Inc. +# GraphemeBreakProperty-16.0.0.txt +# Date: 2024-05-31, 18:09:38 GMT +# © 2024 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database # For documentation, see https://www.unicode.org/reports/tr44/ @@ -27,6 +27,7 @@ 110BD ; Prepend # Cf KAITHI NUMBER SIGN 110CD ; Prepend # Cf KAITHI NUMBER SIGN ABOVE 111C2..111C3 ; Prepend # Lo [2] SHARADA SIGN JIHVAMULIYA..SHARADA SIGN UPADHMANIYA +113D1 ; Prepend # Lo TULU-TIGALARI REPHA 1193F ; Prepend # Lo DIVES AKURU PREFIXED NASAL SIGN 11941 ; Prepend # Lo DIVES AKURU INITIAL RA 11A3A ; Prepend # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA @@ -34,7 +35,7 @@ 11D46 ; Prepend # Lo MASARAM GONDI REPHA 11F02 ; Prepend # Lo KAWI SIGN REPHA -# Total code points: 27 +# Total code points: 28 # ================================================ @@ -106,7 +107,7 @@ E01F0..E0FFF ; Control # Cn [3600] .. 0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA 0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK -0898..089F ; Extend # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; Extend # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08CA..08E1 ; Extend # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA 08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA 093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE @@ -163,8 +164,11 @@ E01F0..E0FFF ; Control # Cn [3600] .. 0C81 ; Extend # Mn KANNADA SIGN CANDRABINDU 0CBC ; Extend # Mn KANNADA SIGN NUKTA 0CBF ; Extend # Mn KANNADA VOWEL SIGN I +0CC0 ; Extend # Mc KANNADA VOWEL SIGN II 0CC2 ; Extend # Mc KANNADA VOWEL SIGN UU 0CC6 ; Extend # Mn KANNADA VOWEL SIGN E +0CC7..0CC8 ; Extend # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI +0CCA..0CCB ; Extend # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO 0CCC..0CCD ; Extend # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA 0CD5..0CD6 ; Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK 0CE2..0CE3 ; Extend # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL @@ -210,7 +214,9 @@ E01F0..E0FFF ; Control # Cn [3600] .. 109D ; Extend # Mn MYANMAR VOWEL SIGN AITON AI 135D..135F ; Extend # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK 1712..1714 ; Extend # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA +1715 ; Extend # Mc TAGALOG SIGN PAMUDPOD 1732..1733 ; Extend # Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U +1734 ; Extend # Mc HANUNOO SIGN PAMUDPOD 1752..1753 ; Extend # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U 1772..1773 ; Extend # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U 17B4..17B5 ; Extend # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA @@ -242,17 +248,22 @@ E01F0..E0FFF ; Control # Cn [3600] .. 1B34 ; Extend # Mn BALINESE SIGN REREKAN 1B35 ; Extend # Mc BALINESE VOWEL SIGN TEDUNG 1B36..1B3A ; Extend # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA +1B3B ; Extend # Mc BALINESE VOWEL SIGN RA REPA TEDUNG 1B3C ; Extend # Mn BALINESE VOWEL SIGN LA LENGA +1B3D ; Extend # Mc BALINESE VOWEL SIGN LA LENGA TEDUNG 1B42 ; Extend # Mn BALINESE VOWEL SIGN PEPET +1B43..1B44 ; Extend # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG 1B6B..1B73 ; Extend # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG 1B80..1B81 ; Extend # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR 1BA2..1BA5 ; Extend # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU 1BA8..1BA9 ; Extend # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG +1BAA ; Extend # Mc SUNDANESE SIGN PAMAAEH 1BAB..1BAD ; Extend # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA 1BE6 ; Extend # Mn BATAK SIGN TOMPI 1BE8..1BE9 ; Extend # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE 1BED ; Extend # Mn BATAK VOWEL SIGN KARO O 1BEF..1BF1 ; Extend # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H +1BF2..1BF3 ; Extend # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN 1C2C..1C33 ; Extend # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T 1C36..1C37 ; Extend # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA 1CD0..1CD2 ; Extend # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA @@ -289,10 +300,12 @@ A8E0..A8F1 ; Extend # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEV A8FF ; Extend # Mn DEVANAGARI VOWEL SIGN AY A926..A92D ; Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU A947..A951 ; Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R +A953 ; Extend # Mc REJANG VIRAMA A980..A982 ; Extend # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR A9B3 ; Extend # Mn JAVANESE SIGN CECAK TELU A9B6..A9B9 ; Extend # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT A9BC..A9BD ; Extend # Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET +A9C0 ; Extend # Mc JAVANESE PANGKON A9E5 ; Extend # Mn MYANMAR SIGN SHAN SAW AA29..AA2E ; Extend # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE AA31..AA32 ; Extend # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE @@ -324,8 +337,9 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 10A3F ; Extend # Mn KHAROSHTHI VIRAMA 10AE5..10AE6 ; Extend # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW 10D24..10D27 ; Extend # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D69..10D6D ; Extend # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK 10EAB..10EAC ; Extend # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK -10EFD..10EFF ; Extend # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EFC..10EFF ; Extend # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F46..10F50 ; Extend # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW 10F82..10F85 ; Extend # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW 11001 ; Extend # Mn BRAHMI SIGN ANUSVARA @@ -342,10 +356,12 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11173 ; Extend # Mn MAHAJANI SIGN NUKTA 11180..11181 ; Extend # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA 111B6..111BE ; Extend # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O +111C0 ; Extend # Mc SHARADA SIGN VIRAMA 111C9..111CC ; Extend # Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK 111CF ; Extend # Mn SHARADA SIGN INVERTED CANDRABINDU 1122F..11231 ; Extend # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI 11234 ; Extend # Mn KHOJKI SIGN ANUSVARA +11235 ; Extend # Mc KHOJKI SIGN VIRAMA 11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA 1123E ; Extend # Mn KHOJKI SIGN SUKUN 11241 ; Extend # Mn KHOJKI VOWEL SIGN VOCALIC R @@ -355,9 +371,20 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 1133B..1133C ; Extend # Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA 1133E ; Extend # Mc GRANTHA VOWEL SIGN AA 11340 ; Extend # Mn GRANTHA VOWEL SIGN II +1134D ; Extend # Mc GRANTHA SIGN VIRAMA 11357 ; Extend # Mc GRANTHA AU LENGTH MARK 11366..1136C ; Extend # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; Extend # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +113B8 ; Extend # Mc TULU-TIGALARI VOWEL SIGN AA +113BB..113C0 ; Extend # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113C2 ; Extend # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; Extend # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113C9 ; Extend # Mc [3] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI AU LENGTH MARK +113CE ; Extend # Mn TULU-TIGALARI SIGN VIRAMA +113CF ; Extend # Mc TULU-TIGALARI SIGN LOOPED VIRAMA +113D0 ; Extend # Mn TULU-TIGALARI CONJOINER +113D2 ; Extend # Mn TULU-TIGALARI GEMINATION MARK +113E1..113E2 ; Extend # Mn [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11438..1143F ; Extend # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI 11442..11444 ; Extend # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA 11446 ; Extend # Mn NEWA SIGN NUKTA @@ -379,14 +406,17 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 116AB ; Extend # Mn TAKRI SIGN ANUSVARA 116AD ; Extend # Mn TAKRI VOWEL SIGN AA 116B0..116B5 ; Extend # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU +116B6 ; Extend # Mc TAKRI SIGN VIRAMA 116B7 ; Extend # Mn TAKRI SIGN NUKTA -1171D..1171F ; Extend # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; Extend # Mn AHOM CONSONANT SIGN MEDIAL LA +1171F ; Extend # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11722..11725 ; Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11727..1172B ; Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER 1182F..11837 ; Extend # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA 11839..1183A ; Extend # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA 11930 ; Extend # Mc DIVES AKURU VOWEL SIGN AA 1193B..1193C ; Extend # Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU +1193D ; Extend # Mc DIVES AKURU SIGN HALANTA 1193E ; Extend # Mn DIVES AKURU VIRAMA 11943 ; Extend # Mn DIVES AKURU SIGN NUKTA 119D4..119D7 ; Extend # Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR @@ -419,20 +449,25 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11F00..11F01 ; Extend # Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA 11F36..11F3A ; Extend # Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R 11F40 ; Extend # Mn KAWI VOWEL SIGN EU +11F41 ; Extend # Mc KAWI SIGN KILLER 11F42 ; Extend # Mn KAWI CONJOINER +11F5A ; Extend # Mn KAWI SIGN NUKTA 13440 ; Extend # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13447..13455 ; Extend # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +1611E..16129 ; Extend # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612D..1612F ; Extend # Mn [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA 16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F4F ; Extend # Mn MIAO SIGN CONSONANT MODIFIER BAR 16F8F..16F92 ; Extend # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16FE4 ; Extend # Mn KHITAN SMALL SCRIPT FILLER +16FF0..16FF1 ; Extend # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY 1BC9D..1BC9E ; Extend # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK 1CF00..1CF2D ; Extend # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT 1CF30..1CF46 ; Extend # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG -1D165 ; Extend # Mc MUSICAL SYMBOL COMBINING STEM +1D165..1D166 ; Extend # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM 1D167..1D169 ; Extend # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 -1D16E..1D172 ; Extend # Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5 +1D16D..1D172 ; Extend # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 1D17B..1D182 ; Extend # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE 1D185..1D18B ; Extend # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE 1D1AA..1D1AD ; Extend # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO @@ -453,13 +488,14 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 1E2AE ; Extend # Mn TOTO SIGN RISING TONE 1E2EC..1E2EF ; Extend # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI 1E4EC..1E4EF ; Extend # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH +1E5EE..1E5EF ; Extend # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR 1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS 1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA 1F3FB..1F3FF ; Extend # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 2130 +# Total code points: 2198 # ================================================ @@ -496,10 +532,8 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 0C41..0C44 ; SpacingMark # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR 0C82..0C83 ; SpacingMark # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 0CBE ; SpacingMark # Mc KANNADA VOWEL SIGN AA -0CC0..0CC1 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN U +0CC1 ; SpacingMark # Mc KANNADA VOWEL SIGN U 0CC3..0CC4 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN VOCALIC R..KANNADA VOWEL SIGN VOCALIC RR -0CC7..0CC8 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI -0CCA..0CCB ; SpacingMark # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO 0CF3 ; SpacingMark # Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT 0D02..0D03 ; SpacingMark # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D3F..0D40 ; SpacingMark # Mc [2] MALAYALAM VOWEL SIGN I..MALAYALAM VOWEL SIGN II @@ -517,8 +551,6 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 103B..103C ; SpacingMark # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA 1056..1057 ; SpacingMark # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR 1084 ; SpacingMark # Mc MYANMAR VOWEL SIGN SHAN E -1715 ; SpacingMark # Mc TAGALOG SIGN PAMUDPOD -1734 ; SpacingMark # Mc HANUNOO SIGN PAMUDPOD 17B6 ; SpacingMark # Mc KHMER VOWEL SIGN AA 17BE..17C5 ; SpacingMark # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU 17C7..17C8 ; SpacingMark # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU @@ -531,17 +563,13 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 1A57 ; SpacingMark # Mc TAI THAM CONSONANT SIGN LA TANG LAI 1A6D..1A72 ; SpacingMark # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI 1B04 ; SpacingMark # Mc BALINESE SIGN BISAH -1B3B ; SpacingMark # Mc BALINESE VOWEL SIGN RA REPA TEDUNG -1B3D..1B41 ; SpacingMark # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG -1B43..1B44 ; SpacingMark # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG +1B3E..1B41 ; SpacingMark # Mc [4] BALINESE VOWEL SIGN TALING..BALINESE VOWEL SIGN TALING REPA TEDUNG 1B82 ; SpacingMark # Mc SUNDANESE SIGN PANGWISAD 1BA1 ; SpacingMark # Mc SUNDANESE CONSONANT SIGN PAMINGKAL 1BA6..1BA7 ; SpacingMark # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG -1BAA ; SpacingMark # Mc SUNDANESE SIGN PAMAAEH 1BE7 ; SpacingMark # Mc BATAK VOWEL SIGN E 1BEA..1BEC ; SpacingMark # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O 1BEE ; SpacingMark # Mc BATAK VOWEL SIGN U -1BF2..1BF3 ; SpacingMark # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN 1C24..1C2B ; SpacingMark # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU 1C34..1C35 ; SpacingMark # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG 1CE1 ; SpacingMark # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA @@ -550,11 +578,11 @@ A823..A824 ; SpacingMark # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI V A827 ; SpacingMark # Mc SYLOTI NAGRI VOWEL SIGN OO A880..A881 ; SpacingMark # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA A8B4..A8C3 ; SpacingMark # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU -A952..A953 ; SpacingMark # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA +A952 ; SpacingMark # Mc REJANG CONSONANT SIGN H A983 ; SpacingMark # Mc JAVANESE SIGN WIGNYAN A9B4..A9B5 ; SpacingMark # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG A9BA..A9BB ; SpacingMark # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE -A9BE..A9C0 ; SpacingMark # Mc [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON +A9BE..A9BF ; SpacingMark # Mc [2] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE CONSONANT SIGN CAKRA AA2F..AA30 ; SpacingMark # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI AA33..AA34 ; SpacingMark # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA AA4D ; SpacingMark # Mc CHAM CONSONANT SIGN FINAL H @@ -574,18 +602,20 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 11145..11146 ; SpacingMark # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI 11182 ; SpacingMark # Mc SHARADA SIGN VISARGA 111B3..111B5 ; SpacingMark # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II -111BF..111C0 ; SpacingMark # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA +111BF ; SpacingMark # Mc SHARADA VOWEL SIGN AU 111CE ; SpacingMark # Mc SHARADA VOWEL SIGN PRISHTHAMATRA E 1122C..1122E ; SpacingMark # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II 11232..11233 ; SpacingMark # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU -11235 ; SpacingMark # Mc KHOJKI SIGN VIRAMA 112E0..112E2 ; SpacingMark # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II 11302..11303 ; SpacingMark # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA 1133F ; SpacingMark # Mc GRANTHA VOWEL SIGN I 11341..11344 ; SpacingMark # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR 11347..11348 ; SpacingMark # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI -1134B..1134D ; SpacingMark # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA +1134B..1134C ; SpacingMark # Mc [2] GRANTHA VOWEL SIGN OO..GRANTHA VOWEL SIGN AU 11362..11363 ; SpacingMark # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +113B9..113BA ; SpacingMark # Mc [2] TULU-TIGALARI VOWEL SIGN I..TULU-TIGALARI VOWEL SIGN II +113CA ; SpacingMark # Mc TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; SpacingMark # Mc [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA 11435..11437 ; SpacingMark # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11440..11441 ; SpacingMark # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU 11445 ; SpacingMark # Mc NEWA SIGN VISARGA @@ -602,13 +632,12 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 1163E ; SpacingMark # Mc MODI SIGN VISARGA 116AC ; SpacingMark # Mc TAKRI SIGN VISARGA 116AE..116AF ; SpacingMark # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II -116B6 ; SpacingMark # Mc TAKRI SIGN VIRAMA +1171E ; SpacingMark # Mc AHOM CONSONANT SIGN MEDIAL RA 11726 ; SpacingMark # Mc AHOM VOWEL SIGN E 1182C..1182E ; SpacingMark # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II 11838 ; SpacingMark # Mc DOGRA SIGN VISARGA 11931..11935 ; SpacingMark # Mc [5] DIVES AKURU VOWEL SIGN I..DIVES AKURU VOWEL SIGN E 11937..11938 ; SpacingMark # Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O -1193D ; SpacingMark # Mc DIVES AKURU SIGN HALANTA 11940 ; SpacingMark # Mc DIVES AKURU MEDIAL YA 11942 ; SpacingMark # Mc DIVES AKURU MEDIAL RA 119D1..119D3 ; SpacingMark # Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II @@ -629,13 +658,10 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 11F03 ; SpacingMark # Mc KAWI SIGN VISARGA 11F34..11F35 ; SpacingMark # Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA 11F3E..11F3F ; SpacingMark # Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI -11F41 ; SpacingMark # Mc KAWI SIGN KILLER +1612A..1612C ; SpacingMark # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA 16F51..16F87 ; SpacingMark # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI -16FF0..16FF1 ; SpacingMark # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY -1D166 ; SpacingMark # Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM -1D16D ; SpacingMark # Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT -# Total code points: 395 +# Total code points: 378 # ================================================ @@ -648,8 +674,10 @@ A960..A97C ; L # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANG 1160..11A7 ; V # Lo [72] HANGUL JUNGSEONG FILLER..HANGUL JUNGSEONG O-YAE D7B0..D7C6 ; V # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E +16D63 ; V # Lo KIRAT RAI VOWEL SIGN AA +16D67..16D6A ; V # Lo [4] KIRAT RAI VOWEL SIGN E..KIRAT RAI VOWEL SIGN AU -# Total code points: 95 +# Total code points: 100 # ================================================ diff --git a/libcxx/utils/data/unicode/GraphemeBreakTest.txt b/libcxx/utils/data/unicode/GraphemeBreakTest.txt index 4c1ed512e4510d..d10c174b6896d3 100644 --- a/libcxx/utils/data/unicode/GraphemeBreakTest.txt +++ b/libcxx/utils/data/unicode/GraphemeBreakTest.txt @@ -1,8 +1,8 @@ -# GraphemeBreakTest-15.1.0.txt -# Date: 2023-08-07, 15:52:55 GMT -# © 2023 Unicode®, Inc. +# GraphemeBreakTest-16.0.0.txt +# Date: 2024-05-02, 15:02:48 GMT +# © 2024 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database # For documentation, see https://www.unicode.org/reports/tr44/ @@ -30,8 +30,8 @@ ÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0020 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (Control) ÷ [0.3] ÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0020 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0020 × 0308 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0020 × 200C ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0020 × 0308 × 200C ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0020 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -48,8 +48,6 @@ ÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0020 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0020 × 0900 ÷ # ÷ [0.2] SPACE (Other) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0020 × 0308 × 0900 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0020 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0020 ÷ 0904 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -62,8 +60,8 @@ ÷ 0020 × 0308 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0020 × 093C ÷ # ÷ [0.2] SPACE (Other) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0020 × 0308 × 093C ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0020 × 0900 ÷ # ÷ [0.2] SPACE (Other) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0020 × 0308 × 0900 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0020 × 094D ÷ # ÷ [0.2] SPACE (Other) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0020 × 0308 × 094D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -78,8 +76,8 @@ ÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 000D ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Control) ÷ [0.3] ÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 000D ÷ 034F ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 000D ÷ 0308 × 034F ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000D ÷ 200C ÷ # ÷ [0.2] (CR) ÷ [4.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 000D ÷ 0308 × 200C ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 000D ÷ 0600 ÷ # ÷ [0.2] (CR) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -96,8 +94,6 @@ ÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 000D ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 000D ÷ 0900 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 000D ÷ 0308 × 0900 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 000D ÷ 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 000D ÷ 0904 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -110,8 +106,8 @@ ÷ 000D ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 000D ÷ 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 093C ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 0308 × 093C ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 0900 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 0308 × 0900 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 000D ÷ 094D ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 000D ÷ 0308 × 094D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 000D ÷ 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -126,8 +122,8 @@ ÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 000A ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Control) ÷ [0.3] ÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 000A ÷ 034F ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 000A ÷ 0308 × 034F ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000A ÷ 200C ÷ # ÷ [0.2] (LF) ÷ [4.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 000A ÷ 0308 × 200C ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 000A ÷ 0600 ÷ # ÷ [0.2] (LF) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -144,8 +140,6 @@ ÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 000A ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 000A ÷ 0900 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 000A ÷ 0308 × 0900 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 000A ÷ 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 000A ÷ 0904 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -158,8 +152,8 @@ ÷ 000A ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 000A ÷ 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 093C ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 0308 × 093C ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 0900 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 0308 × 0900 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 000A ÷ 094D ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 000A ÷ 0308 × 094D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 000A ÷ 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -174,8 +168,8 @@ ÷ 0001 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0001 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Control) ÷ [0.3] ÷ 0001 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0001 ÷ 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0001 ÷ 0308 × 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0001 ÷ 200C ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0001 ÷ 0308 × 200C ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0001 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -192,8 +186,6 @@ ÷ 0001 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0001 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0001 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0001 ÷ 0900 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0001 ÷ 0308 × 0900 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0001 ÷ 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0001 ÷ 0308 × 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0001 ÷ 0904 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -206,62 +198,60 @@ ÷ 0001 ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0001 ÷ 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 0308 × 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 093C ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 0308 × 093C ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 0900 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 0308 × 0900 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 094D ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 0308 × 094D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 0308 × 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Other) ÷ [0.3] ÷ 0001 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 034F ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 034F × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 034F ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (CR) ÷ [0.3] -÷ 034F × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 034F ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (LF) ÷ [0.3] -÷ 034F × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 034F ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (Control) ÷ [0.3] -÷ 034F × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 034F × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 034F × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 034F ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 034F × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 034F ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 034F × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 034F × 0A03 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 034F × 0308 × 0A03 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 034F ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 034F × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 034F ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 034F × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 034F ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 034F × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 034F ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 034F × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 034F ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 034F × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 034F × 0900 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F × 0308 × 0900 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F ÷ 0904 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 034F × 0308 ÷ 0904 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 034F ÷ 0D4E ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F × 0308 ÷ 0D4E ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F ÷ 0915 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 034F × 0308 ÷ 0915 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 034F ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 034F × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 034F × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 034F × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 034F × 093C ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 034F × 0308 × 093C ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 034F × 094D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 034F × 0308 × 094D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 034F × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 034F × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 034F ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] (Other) ÷ [0.3] -÷ 034F × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 200C ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 200C × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 200C ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [5.0] (CR) ÷ [0.3] +÷ 200C × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 200C ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [5.0] (LF) ÷ [0.3] +÷ 200C × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 200C ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [5.0] (Control) ÷ [0.3] +÷ 200C × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 200C × 200C ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 200C × 0308 × 200C ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 200C ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200C ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 200C × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 200C × 0A03 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200C × 0308 × 0A03 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200C ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200C × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200C ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200C × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200C ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200C × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200C ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200C × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200C ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200C × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200C × 0903 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] +÷ 200C × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] +÷ 200C ÷ 0904 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] +÷ 200C × 0308 ÷ 0904 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] +÷ 200C ÷ 0D4E ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] +÷ 200C × 0308 ÷ 0D4E ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] +÷ 200C ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] +÷ 200C × 0308 ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] +÷ 200C ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 200C × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 200C × 0300 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 200C × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 200C × 0900 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 200C × 0308 × 0900 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 200C × 094D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] +÷ 200C × 0308 × 094D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] +÷ 200C × 200D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 200C × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 200C ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] (Other) ÷ [0.3] +÷ 200C × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] ÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (CR) ÷ [0.3] @@ -270,8 +260,8 @@ ÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (Control) ÷ [0.3] ÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 1F1E6 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 1F1E6 × 0308 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1F1E6 × 200C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 1F1E6 × 0308 × 200C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1F1E6 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -288,8 +278,6 @@ ÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1F1E6 × 0900 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1F1E6 × 0308 × 0900 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1F1E6 ÷ 0904 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -302,8 +290,8 @@ ÷ 1F1E6 × 0308 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 × 093C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 × 0308 × 093C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 × 0900 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 × 0308 × 0900 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 1F1E6 × 094D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1F1E6 × 0308 × 094D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -318,8 +306,8 @@ ÷ 0600 × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0600 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (Control) ÷ [0.3] ÷ 0600 × 0308 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0600 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0600 × 0308 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0600 × 200C ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0600 × 0308 × 200C ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0600 × 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0600 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0600 × 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -336,8 +324,6 @@ ÷ 0600 × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0600 × AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0600 × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0600 × 0900 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0600 × 0308 × 0900 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0600 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0600 × 0308 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0600 × 0904 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -350,8 +336,8 @@ ÷ 0600 × 0308 ÷ 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0600 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0600 × 0308 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0600 × 093C ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0600 × 0308 × 093C ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0600 × 0900 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0600 × 0308 × 0900 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0600 × 094D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0600 × 0308 × 094D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0600 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -366,8 +352,8 @@ ÷ 0A03 × 0308 ÷ 000A ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0A03 ÷ 0001 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [5.0] (Control) ÷ [0.3] ÷ 0A03 × 0308 ÷ 0001 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0A03 × 034F ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0A03 × 0308 × 034F ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0A03 × 200C ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0A03 × 0308 × 200C ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0A03 ÷ 1F1E6 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0A03 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0A03 ÷ 0600 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -384,8 +370,6 @@ ÷ 0A03 × 0308 ÷ AC00 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0A03 ÷ AC01 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0A03 × 0308 ÷ AC01 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0A03 × 0900 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0A03 × 0308 × 0900 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0A03 × 0903 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0A03 × 0308 × 0903 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0A03 ÷ 0904 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -398,8 +382,8 @@ ÷ 0A03 × 0308 ÷ 231A ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0A03 × 0300 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0A03 × 0308 × 0300 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0A03 × 093C ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0A03 × 0308 × 093C ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0A03 × 0900 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0A03 × 0308 × 0900 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0A03 × 094D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0A03 × 0308 × 094D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0A03 × 200D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -414,8 +398,8 @@ ÷ 1100 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 1100 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (Control) ÷ [0.3] ÷ 1100 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 1100 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 1100 × 0308 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1100 × 200C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 1100 × 0308 × 200C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1100 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -432,8 +416,6 @@ ÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 1100 × AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1100 × 0900 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1100 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 1100 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1100 ÷ 0904 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -446,8 +428,8 @@ ÷ 1100 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1100 × 093C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1100 × 0308 × 093C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1100 × 0900 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1100 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 1100 × 094D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1100 × 0308 × 094D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -462,8 +444,8 @@ ÷ 1160 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 1160 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (Control) ÷ [0.3] ÷ 1160 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 1160 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 1160 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1160 × 200C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 1160 × 0308 × 200C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1160 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -480,8 +462,6 @@ ÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 1160 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1160 × 0900 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1160 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 1160 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1160 ÷ 0904 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -494,8 +474,8 @@ ÷ 1160 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1160 × 093C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1160 × 0308 × 093C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1160 × 0900 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1160 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 1160 × 094D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1160 × 0308 × 094D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -510,8 +490,8 @@ ÷ 11A8 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 11A8 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (Control) ÷ [0.3] ÷ 11A8 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 11A8 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 11A8 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 11A8 × 200C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 11A8 × 0308 × 200C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 11A8 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -528,8 +508,6 @@ ÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 11A8 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 11A8 × 0900 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 11A8 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 11A8 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 11A8 ÷ 0904 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -542,8 +520,8 @@ ÷ 11A8 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 11A8 × 093C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 11A8 × 0308 × 093C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 11A8 × 0900 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 11A8 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 11A8 × 094D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 11A8 × 0308 × 094D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -558,8 +536,8 @@ ÷ AC00 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ AC00 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (Control) ÷ [0.3] ÷ AC00 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ AC00 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ AC00 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC00 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ AC00 × 0308 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ AC00 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -576,8 +554,6 @@ ÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ AC00 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ AC00 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ AC00 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ AC00 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ AC00 ÷ 0904 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -590,8 +566,8 @@ ÷ AC00 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ AC00 × 093C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ AC00 × 0308 × 093C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ AC00 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ AC00 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ AC00 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ AC00 × 0308 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -606,8 +582,8 @@ ÷ AC01 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ AC01 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (Control) ÷ [0.3] ÷ AC01 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ AC01 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ AC01 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC01 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ AC01 × 0308 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ AC01 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -624,8 +600,6 @@ ÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ AC01 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ AC01 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ AC01 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ AC01 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ AC01 ÷ 0904 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -638,62 +612,14 @@ ÷ AC01 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ AC01 × 093C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ AC01 × 0308 × 093C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ AC01 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ AC01 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ AC01 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ AC01 × 0308 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ AC01 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] (Other) ÷ [0.3] ÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0900 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0900 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0900 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [5.0] (CR) ÷ [0.3] -÷ 0900 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0900 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [5.0] (LF) ÷ [0.3] -÷ 0900 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0900 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [5.0] (Control) ÷ [0.3] -÷ 0900 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0900 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0900 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0900 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0900 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0900 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0900 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0900 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0900 × 0308 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0900 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0900 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0900 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0900 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0900 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0900 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0900 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0900 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0900 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0900 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0900 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0308 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0308 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0900 × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0900 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0900 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0900 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0900 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0900 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0900 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0900 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] (Other) ÷ [0.3] -÷ 0900 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] ÷ 0903 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 0903 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [5.0] (CR) ÷ [0.3] @@ -702,8 +628,8 @@ ÷ 0903 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0903 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [5.0] (Control) ÷ [0.3] ÷ 0903 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0903 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0903 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0903 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0903 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0903 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -720,8 +646,6 @@ ÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0903 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0903 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0903 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0903 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0903 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -734,8 +658,8 @@ ÷ 0903 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0903 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0903 × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0903 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0903 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0903 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0903 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -750,8 +674,8 @@ ÷ 0904 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0904 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [5.0] (Control) ÷ [0.3] ÷ 0904 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0904 × 034F ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0904 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0904 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0904 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0904 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0904 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0904 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -768,8 +692,6 @@ ÷ 0904 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0904 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0904 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0904 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0904 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0904 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0904 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0904 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -782,8 +704,8 @@ ÷ 0904 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0904 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0904 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0904 × 093C ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0904 × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0904 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0904 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0904 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0904 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0904 × 200D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -798,8 +720,8 @@ ÷ 0D4E × 0308 ÷ 000A ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0D4E ÷ 0001 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [5.0] (Control) ÷ [0.3] ÷ 0D4E × 0308 ÷ 0001 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0D4E × 034F ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0D4E × 0308 × 034F ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0D4E × 200C ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0D4E × 0308 × 200C ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0D4E × 1F1E6 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0D4E × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0D4E × 0600 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -816,8 +738,6 @@ ÷ 0D4E × 0308 ÷ AC00 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0D4E × AC01 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0D4E × 0308 ÷ AC01 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0D4E × 0900 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0D4E × 0308 × 0900 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0D4E × 0903 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0D4E × 0308 × 0903 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0D4E × 0904 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -830,8 +750,8 @@ ÷ 0D4E × 0308 ÷ 231A ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0D4E × 0300 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0D4E × 0308 × 0300 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 093C ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 0308 × 093C ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0D4E × 0900 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0D4E × 0308 × 0900 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0D4E × 094D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0D4E × 0308 × 094D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0D4E × 200D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -846,8 +766,8 @@ ÷ 0915 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0915 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [5.0] (Control) ÷ [0.3] ÷ 0915 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0915 × 034F ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0915 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0915 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0915 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0915 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0915 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0915 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -864,8 +784,6 @@ ÷ 0915 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0915 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0915 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0915 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0915 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0915 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0915 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0915 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -878,8 +796,8 @@ ÷ 0915 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0915 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0915 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0915 × 093C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0915 × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0915 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0915 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0915 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0915 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0915 × 200D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -894,8 +812,8 @@ ÷ 231A × 0308 ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 231A ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (Control) ÷ [0.3] ÷ 231A × 0308 ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 231A × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 231A × 0308 × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 231A × 200C ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 231A × 0308 × 200C ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 231A ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 231A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 231A ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -912,8 +830,6 @@ ÷ 231A × 0308 ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 231A ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 231A × 0308 ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 231A × 0900 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 231A × 0308 × 0900 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 231A × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 231A × 0308 × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 231A ÷ 0904 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -926,8 +842,8 @@ ÷ 231A × 0308 ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 231A × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 231A × 0308 × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 231A × 093C ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 231A × 0308 × 093C ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 231A × 0900 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 231A × 0308 × 0900 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 231A × 094D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 231A × 0308 × 094D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 231A × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -942,8 +858,8 @@ ÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] ÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0300 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0300 × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0300 × 200C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0300 × 0308 × 200C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0300 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -960,8 +876,6 @@ ÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0300 × 0900 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0300 × 0308 × 0900 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0300 ÷ 0904 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -974,62 +888,60 @@ ÷ 0300 × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0300 × 093C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0300 × 0308 × 093C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0300 × 0900 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0300 × 0308 × 0900 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0300 × 094D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0300 × 0308 × 094D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] ÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 093C ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 093C × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 093C ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 093C × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 093C ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 093C × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 093C ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 093C × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 093C × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 093C × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 093C ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 093C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 093C ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 093C × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 093C × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 093C × 0308 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 093C ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 093C × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 093C ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 093C × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 093C ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 093C × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 093C ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 093C × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 093C ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 093C × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 093C × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 093C × 0308 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 093C ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C × 0308 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 093C × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 093C ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 093C × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 093C × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 093C × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 093C × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 093C × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 093C × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 093C × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 093C × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 093C × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 093C ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 093C × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0900 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0900 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0900 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0900 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0900 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0900 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0900 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0900 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0900 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0900 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0900 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0900 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0900 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0900 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0900 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0900 × 0308 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0900 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0900 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0900 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0900 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0900 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0900 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0900 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0900 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0900 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0900 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0900 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 × 0308 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 × 0308 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] +÷ 0900 × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] +÷ 0900 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0900 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0900 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0900 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0900 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0900 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0900 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] +÷ 0900 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] +÷ 0900 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0900 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0900 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0900 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] ÷ 094D ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 094D × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 094D ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] @@ -1038,8 +950,8 @@ ÷ 094D × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 094D ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] ÷ 094D × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 094D × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 094D × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 094D × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 094D × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 094D ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 094D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 094D ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -1056,8 +968,6 @@ ÷ 094D × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 094D ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 094D × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 094D × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 094D × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 094D × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 094D × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 094D ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -1070,8 +980,8 @@ ÷ 094D × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 094D × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 094D × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 094D × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 094D × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 094D × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 094D × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 094D × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 094D × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 094D × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -1086,8 +996,8 @@ ÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] ÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 200D × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 200D × 0308 × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 200D × 200C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 200D × 0308 × 200C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 200D ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -1104,8 +1014,6 @@ ÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 200D × 0900 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 200D × 0308 × 0900 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 200D ÷ 0904 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -1118,8 +1026,8 @@ ÷ 200D × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 200D × 093C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 200D × 0308 × 093C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 200D × 0900 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 200D × 0308 × 0900 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 200D × 094D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 200D × 0308 × 094D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -1134,8 +1042,8 @@ ÷ 0378 × 0308 ÷ 000A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0378 ÷ 0001 ÷ # ÷ [0.2] (Other) ÷ [5.0] (Control) ÷ [0.3] ÷ 0378 × 0308 ÷ 0001 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0378 × 034F ÷ # ÷ [0.2] (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0378 × 0308 × 034F ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0378 × 200C ÷ # ÷ [0.2] (Other) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0378 × 0308 × 200C ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0378 ÷ 0600 ÷ # ÷ [0.2] (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -1152,8 +1060,6 @@ ÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0378 ÷ AC01 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0378 × 0900 ÷ # ÷ [0.2] (Other) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0378 × 0308 × 0900 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0378 × 0903 ÷ # ÷ [0.2] (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0378 ÷ 0904 ÷ # ÷ [0.2] (Other) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -1166,8 +1072,8 @@ ÷ 0378 × 0308 ÷ 231A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0378 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0378 × 093C ÷ # ÷ [0.2] (Other) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0378 × 0308 × 093C ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0378 × 0900 ÷ # ÷ [0.2] (Other) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0378 × 0308 × 0900 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0378 × 094D ÷ # ÷ [0.2] (Other) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0378 × 0308 × 094D ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0378 × 200D ÷ # ÷ [0.2] (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -1190,10 +1096,10 @@ ÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] ÷ 0061 × 0903 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] ÷ 0061 ÷ 0600 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) × [9.2] LATIN SMALL LETTER B (Other) ÷ [0.3] -÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3] -÷ 0061 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3] -÷ 0061 × 1F3FF ÷ 1F476 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] -÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [0.3] +÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 0061 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 0061 × 1F3FF ÷ 1F476 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [999.0] BABY (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [0.3] ÷ 1F6D1 × 200D × 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] ÷ 0061 × 200D ÷ 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] ÷ 2701 × 200D × 2701 ÷ # ÷ [0.2] UPPER BLADE SCISSORS (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] UPPER BLADE SCISSORS (Other) ÷ [0.3] @@ -1210,6 +1116,6 @@ ÷ 003F × 094D ÷ 0924 ÷ # ÷ [0.2] QUESTION MARK (Other) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] ÷ 0915 × 094D × 094D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.3] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] # -# Lines: 1187 +# Lines: 1093 # # EOF diff --git a/libcxx/utils/data/unicode/emoji-data.txt b/libcxx/utils/data/unicode/emoji-data.txt index 0ba10e9ce4c9ac..ff99028248b5fa 100644 --- a/libcxx/utils/data/unicode/emoji-data.txt +++ b/libcxx/utils/data/unicode/emoji-data.txt @@ -1,11 +1,11 @@ # emoji-data.txt -# Date: 2023-02-01, 02:22:54 GMT -# © 2023 Unicode®, Inc. +# Date: 2024-05-01, 21:25:24 GMT +# © 2024 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Emoji Data for UTS #51 -# Used with Emoji Version 15.1 and subsequent minor revisions (if any) +# Used with Emoji Version 16.0 and subsequent minor revisions (if any) # # For documentation and usage, see https://www.unicode.org/reports/tr51 # @@ -407,6 +407,8 @@ 1FA80..1FA82 ; Emoji # E12.0 [3] (🪀..🪂) yo-yo..parachute 1FA83..1FA86 ; Emoji # E13.0 [4] (🪃..🪆) boomerang..nesting dolls 1FA87..1FA88 ; Emoji # E15.0 [2] (🪇..🪈) maracas..flute +1FA89 ; Emoji # E16.0 [1] (🪉) harp +1FA8F ; Emoji # E16.0 [1] (🪏) shovel 1FA90..1FA95 ; Emoji # E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Emoji # E13.0 [19] (🪖..🪨) military helmet..rock 1FAA9..1FAAC ; Emoji # E14.0 [4] (🪩..🪬) mirror ball..hamsa @@ -414,19 +416,24 @@ 1FAB0..1FAB6 ; Emoji # E13.0 [7] (🪰..🪶) fly..feather 1FAB7..1FABA ; Emoji # E14.0 [4] (🪷..🪺) lotus..nest with eggs 1FABB..1FABD ; Emoji # E15.0 [3] (🪻..🪽) hyacinth..wing +1FABE ; Emoji # E16.0 [1] (🪾) leafless tree 1FABF ; Emoji # E15.0 [1] (🪿) goose 1FAC0..1FAC2 ; Emoji # E13.0 [3] (🫀..🫂) anatomical heart..people hugging 1FAC3..1FAC5 ; Emoji # E14.0 [3] (🫃..🫅) pregnant man..person with crown +1FAC6 ; Emoji # E16.0 [1] (🫆) fingerprint 1FACE..1FACF ; Emoji # E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Emoji # E13.0 [7] (🫐..🫖) blueberries..teapot 1FAD7..1FAD9 ; Emoji # E14.0 [3] (🫗..🫙) pouring liquid..jar 1FADA..1FADB ; Emoji # E15.0 [2] (🫚..🫛) ginger root..pea pod +1FADC ; Emoji # E16.0 [1] (🫜) root vegetable +1FADF ; Emoji # E16.0 [1] (🫟) splatter 1FAE0..1FAE7 ; Emoji # E14.0 [8] (🫠..🫧) melting face..bubbles 1FAE8 ; Emoji # E15.0 [1] (🫨) shaking face +1FAE9 ; Emoji # E16.0 [1] (🫩) face with bags under eyes 1FAF0..1FAF6 ; Emoji # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands 1FAF7..1FAF8 ; Emoji # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand -# Total elements: 1424 +# Total elements: 1431 # ================================================ @@ -696,6 +703,8 @@ 1FA80..1FA82 ; Emoji_Presentation # E12.0 [3] (🪀..🪂) yo-yo..parachute 1FA83..1FA86 ; Emoji_Presentation # E13.0 [4] (🪃..🪆) boomerang..nesting dolls 1FA87..1FA88 ; Emoji_Presentation # E15.0 [2] (🪇..🪈) maracas..flute +1FA89 ; Emoji_Presentation # E16.0 [1] (🪉) harp +1FA8F ; Emoji_Presentation # E16.0 [1] (🪏) shovel 1FA90..1FA95 ; Emoji_Presentation # E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Emoji_Presentation # E13.0 [19] (🪖..🪨) military helmet..rock 1FAA9..1FAAC ; Emoji_Presentation # E14.0 [4] (🪩..🪬) mirror ball..hamsa @@ -703,19 +712,24 @@ 1FAB0..1FAB6 ; Emoji_Presentation # E13.0 [7] (🪰..🪶) fly..feather 1FAB7..1FABA ; Emoji_Presentation # E14.0 [4] (🪷..🪺) lotus..nest with eggs 1FABB..1FABD ; Emoji_Presentation # E15.0 [3] (🪻..🪽) hyacinth..wing +1FABE ; Emoji_Presentation # E16.0 [1] (🪾) leafless tree 1FABF ; Emoji_Presentation # E15.0 [1] (🪿) goose 1FAC0..1FAC2 ; Emoji_Presentation # E13.0 [3] (🫀..🫂) anatomical heart..people hugging 1FAC3..1FAC5 ; Emoji_Presentation # E14.0 [3] (🫃..🫅) pregnant man..person with crown +1FAC6 ; Emoji_Presentation # E16.0 [1] (🫆) fingerprint 1FACE..1FACF ; Emoji_Presentation # E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Emoji_Presentation # E13.0 [7] (🫐..🫖) blueberries..teapot 1FAD7..1FAD9 ; Emoji_Presentation # E14.0 [3] (🫗..🫙) pouring liquid..jar 1FADA..1FADB ; Emoji_Presentation # E15.0 [2] (🫚..🫛) ginger root..pea pod +1FADC ; Emoji_Presentation # E16.0 [1] (🫜) root vegetable +1FADF ; Emoji_Presentation # E16.0 [1] (🫟) splatter 1FAE0..1FAE7 ; Emoji_Presentation # E14.0 [8] (🫠..🫧) melting face..bubbles 1FAE8 ; Emoji_Presentation # E15.0 [1] (🫨) shaking face +1FAE9 ; Emoji_Presentation # E16.0 [1] (🫩) face with bags under eyes 1FAF0..1FAF6 ; Emoji_Presentation # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands 1FAF7..1FAF8 ; Emoji_Presentation # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand -# Total elements: 1205 +# Total elements: 1212 # ================================================ @@ -1289,7 +1303,9 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1FA80..1FA82 ; Extended_Pictographic# E12.0 [3] (🪀..🪂) yo-yo..parachute 1FA83..1FA86 ; Extended_Pictographic# E13.0 [4] (🪃..🪆) boomerang..nesting dolls 1FA87..1FA88 ; Extended_Pictographic# E15.0 [2] (🪇..🪈) maracas..flute -1FA89..1FA8F ; Extended_Pictographic# E0.0 [7] (🪉..🪏) .. +1FA89 ; Extended_Pictographic# E16.0 [1] (🪉) harp +1FA8A..1FA8E ; Extended_Pictographic# E0.0 [5] (🪊..🪎) .. +1FA8F ; Extended_Pictographic# E16.0 [1] (🪏) shovel 1FA90..1FA95 ; Extended_Pictographic# E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Extended_Pictographic# E13.0 [19] (🪖..🪨) military helmet..rock 1FAA9..1FAAC ; Extended_Pictographic# E14.0 [4] (🪩..🪬) mirror ball..hamsa @@ -1297,19 +1313,23 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1FAB0..1FAB6 ; Extended_Pictographic# E13.0 [7] (🪰..🪶) fly..feather 1FAB7..1FABA ; Extended_Pictographic# E14.0 [4] (🪷..🪺) lotus..nest with eggs 1FABB..1FABD ; Extended_Pictographic# E15.0 [3] (🪻..🪽) hyacinth..wing -1FABE ; Extended_Pictographic# E0.0 [1] (🪾) +1FABE ; Extended_Pictographic# E16.0 [1] (🪾) leafless tree 1FABF ; Extended_Pictographic# E15.0 [1] (🪿) goose 1FAC0..1FAC2 ; Extended_Pictographic# E13.0 [3] (🫀..🫂) anatomical heart..people hugging 1FAC3..1FAC5 ; Extended_Pictographic# E14.0 [3] (🫃..🫅) pregnant man..person with crown -1FAC6..1FACD ; Extended_Pictographic# E0.0 [8] (🫆..🫍) .. +1FAC6 ; Extended_Pictographic# E16.0 [1] (🫆) fingerprint +1FAC7..1FACD ; Extended_Pictographic# E0.0 [7] (🫇..🫍) .. 1FACE..1FACF ; Extended_Pictographic# E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Extended_Pictographic# E13.0 [7] (🫐..🫖) blueberries..teapot 1FAD7..1FAD9 ; Extended_Pictographic# E14.0 [3] (🫗..🫙) pouring liquid..jar 1FADA..1FADB ; Extended_Pictographic# E15.0 [2] (🫚..🫛) ginger root..pea pod -1FADC..1FADF ; Extended_Pictographic# E0.0 [4] (🫜..🫟) .. +1FADC ; Extended_Pictographic# E16.0 [1] (🫜) root vegetable +1FADD..1FADE ; Extended_Pictographic# E0.0 [2] (🫝..🫞) .. +1FADF ; Extended_Pictographic# E16.0 [1] (🫟) splatter 1FAE0..1FAE7 ; Extended_Pictographic# E14.0 [8] (🫠..🫧) melting face..bubbles 1FAE8 ; Extended_Pictographic# E15.0 [1] (🫨) shaking face -1FAE9..1FAEF ; Extended_Pictographic# E0.0 [7] (🫩..🫯) .. +1FAE9 ; Extended_Pictographic# E16.0 [1] (🫩) face with bags under eyes +1FAEA..1FAEF ; Extended_Pictographic# E0.0 [6] (🫪..🫯) .. 1FAF0..1FAF6 ; Extended_Pictographic# E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands 1FAF7..1FAF8 ; Extended_Pictographic# E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand 1FAF9..1FAFF ; Extended_Pictographic# E0.0 [7] (🫹..🫿) .. From libcxx-commits at lists.llvm.org Tue Feb 4 08:28:16 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Tue, 04 Feb 2025 08:28:16 -0800 (PST) Subject: [libcxx-commits] [libcxx] [lib++][Format] Updates Unicode database. (PR #125712) In-Reply-To: Message-ID: <67a24020.050a0220.99893.e45a@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-libcxx Author: Mark de Wever (mordante)
Changes Updates the databease to the Unicode release 16.0.0. The algorithms of the Grapheme clustering rules have not changed. --- Patch is 591.34 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/125712.diff 12 Files Affected: - (modified) libcxx/docs/ReleaseNotes/21.rst (+1) - (modified) libcxx/include/__format/escaped_output_table.h (+53-29) - (modified) libcxx/include/__format/extended_grapheme_cluster_table.h (+52-47) - (modified) libcxx/include/__format/indic_conjunct_break_table.h (+257-55) - (modified) libcxx/include/__format/width_estimation_table.h (+11-8) - (modified) libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h (+531-813) - (modified) libcxx/utils/data/unicode/DerivedCoreProperties.txt (+682-152) - (modified) libcxx/utils/data/unicode/DerivedGeneralCategory.txt (+148-58) - (modified) libcxx/utils/data/unicode/EastAsianWidth.txt (+90-25) - (modified) libcxx/utils/data/unicode/GraphemeBreakProperty.txt (+62-34) - (modified) libcxx/utils/data/unicode/GraphemeBreakTest.txt (+185-279) - (modified) libcxx/utils/data/unicode/emoji-data.txt (+31-11) ``````````diff diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad3942..24393607970238 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -46,6 +46,7 @@ Improvements and New Features - The ``std::ranges::{copy, copy_n, copy_backward}`` algorithms have been optimized for ``std::vector::iterator``\s, resulting in a performance improvement of up to 2000x. +- Updated formatting library to Unicode 16.0.0. Deprecations and Removals ------------------------- diff --git a/libcxx/include/__format/escaped_output_table.h b/libcxx/include/__format/escaped_output_table.h index 7a0b35239861e0..1401b4637d8396 100644 --- a/libcxx/include/__format/escaped_output_table.h +++ b/libcxx/include/__format/escaped_output_table.h @@ -109,7 +109,7 @@ namespace __escaped_output_table { /// - bits [14, 31] The lower bound code point of the range. The upper bound of /// the range is lower bound + size. Note the code expects code units the fit /// into 18 bits, instead of the 21 bits needed for the full Unicode range. -_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[735] = { 0x00000020 /* 00000000 - 00000020 [ 33] */, 0x001fc021 /* 0000007f - 000000a0 [ 34] */, 0x002b4000 /* 000000ad - 000000ad [ 1] */, @@ -136,7 +136,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x02170001 /* 0000085c - 0000085d [ 2] */, 0x0217c000 /* 0000085f - 0000085f [ 1] */, 0x021ac004 /* 0000086b - 0000086f [ 5] */, - 0x0223c008 /* 0000088f - 00000897 [ 9] */, + 0x0223c007 /* 0000088f - 00000896 [ 8] */, 0x02388000 /* 000008e2 - 000008e2 [ 1] */, 0x02610000 /* 00000984 - 00000984 [ 1] */, 0x02634001 /* 0000098d - 0000098e [ 2] */, @@ -331,12 +331,11 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x06a68005 /* 00001a9a - 00001a9f [ 6] */, 0x06ab8001 /* 00001aae - 00001aaf [ 2] */, 0x06b3c030 /* 00001acf - 00001aff [ 49] */, - 0x06d34002 /* 00001b4d - 00001b4f [ 3] */, - 0x06dfc000 /* 00001b7f - 00001b7f [ 1] */, + 0x06d34000 /* 00001b4d - 00001b4d [ 1] */, 0x06fd0007 /* 00001bf4 - 00001bfb [ 8] */, 0x070e0002 /* 00001c38 - 00001c3a [ 3] */, 0x07128002 /* 00001c4a - 00001c4c [ 3] */, - 0x07224006 /* 00001c89 - 00001c8f [ 7] */, + 0x0722c004 /* 00001c8b - 00001c8f [ 5] */, 0x072ec001 /* 00001cbb - 00001cbc [ 2] */, 0x07320007 /* 00001cc8 - 00001ccf [ 8] */, 0x073ec004 /* 00001cfb - 00001cff [ 5] */, @@ -364,7 +363,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x0830400e /* 000020c1 - 000020cf [ 15] */, 0x083c400e /* 000020f1 - 000020ff [ 15] */, 0x08630003 /* 0000218c - 0000218f [ 4] */, - 0x0909c018 /* 00002427 - 0000243f [ 25] */, + 0x090a8015 /* 0000242a - 0000243f [ 22] */, 0x0912c014 /* 0000244b - 0000245f [ 21] */, 0x0add0001 /* 00002b74 - 00002b75 [ 2] */, 0x0ae58000 /* 00002b96 - 00002b96 [ 1] */, @@ -393,16 +392,16 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x0c400004 /* 00003100 - 00003104 [ 5] */, 0x0c4c0000 /* 00003130 - 00003130 [ 1] */, 0x0c63c000 /* 0000318f - 0000318f [ 1] */, - 0x0c79000a /* 000031e4 - 000031ee [ 11] */, + 0x0c798008 /* 000031e6 - 000031ee [ 9] */, 0x0c87c000 /* 0000321f - 0000321f [ 1] */, 0x29234002 /* 0000a48d - 0000a48f [ 3] */, 0x2931c008 /* 0000a4c7 - 0000a4cf [ 9] */, 0x298b0013 /* 0000a62c - 0000a63f [ 20] */, 0x29be0007 /* 0000a6f8 - 0000a6ff [ 8] */, - 0x29f2c004 /* 0000a7cb - 0000a7cf [ 5] */, + 0x29f38001 /* 0000a7ce - 0000a7cf [ 2] */, 0x29f48000 /* 0000a7d2 - 0000a7d2 [ 1] */, 0x29f50000 /* 0000a7d4 - 0000a7d4 [ 1] */, - 0x29f68017 /* 0000a7da - 0000a7f1 [ 24] */, + 0x29f74014 /* 0000a7dd - 0000a7f1 [ 21] */, 0x2a0b4002 /* 0000a82d - 0000a82f [ 3] */, 0x2a0e8005 /* 0000a83a - 0000a83f [ 6] */, 0x2a1e0007 /* 0000a878 - 0000a87f [ 8] */, @@ -491,7 +490,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x41688000 /* 000105a2 - 000105a2 [ 1] */, 0x416c8000 /* 000105b2 - 000105b2 [ 1] */, 0x416e8000 /* 000105ba - 000105ba [ 1] */, - 0x416f4042 /* 000105bd - 000105ff [ 67] */, + 0x416f4002 /* 000105bd - 000105bf [ 3] */, + 0x417d000b /* 000105f4 - 000105ff [ 12] */, 0x41cdc008 /* 00010737 - 0001073f [ 9] */, 0x41d58009 /* 00010756 - 0001075f [ 10] */, 0x41da0017 /* 00010768 - 0001077f [ 24] */, @@ -534,11 +534,15 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x432cc00c /* 00010cb3 - 00010cbf [ 13] */, 0x433cc006 /* 00010cf3 - 00010cf9 [ 7] */, 0x434a0007 /* 00010d28 - 00010d2f [ 8] */, - 0x434e8125 /* 00010d3a - 00010e5f [ 294] */, + 0x434e8005 /* 00010d3a - 00010d3f [ 6] */, + 0x43598002 /* 00010d66 - 00010d68 [ 3] */, + 0x43618007 /* 00010d86 - 00010d8d [ 8] */, + 0x436400cf /* 00010d90 - 00010e5f [ 208] */, 0x439fc000 /* 00010e7f - 00010e7f [ 1] */, 0x43aa8000 /* 00010eaa - 00010eaa [ 1] */, 0x43ab8001 /* 00010eae - 00010eaf [ 2] */, - 0x43ac804a /* 00010eb2 - 00010efc [ 75] */, + 0x43ac800f /* 00010eb2 - 00010ec1 [ 16] */, + 0x43b14036 /* 00010ec5 - 00010efb [ 55] */, 0x43ca0007 /* 00010f28 - 00010f2f [ 8] */, 0x43d68015 /* 00010f5a - 00010f6f [ 22] */, 0x43e28025 /* 00010f8a - 00010faf [ 38] */, @@ -578,7 +582,18 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x44d60004 /* 00011358 - 0001135c [ 5] */, 0x44d90001 /* 00011364 - 00011365 [ 2] */, 0x44db4002 /* 0001136d - 0001136f [ 3] */, - 0x44dd408a /* 00011375 - 000113ff [ 139] */, + 0x44dd400a /* 00011375 - 0001137f [ 11] */, + 0x44e28000 /* 0001138a - 0001138a [ 1] */, + 0x44e30001 /* 0001138c - 0001138d [ 2] */, + 0x44e3c000 /* 0001138f - 0001138f [ 1] */, + 0x44ed8000 /* 000113b6 - 000113b6 [ 1] */, + 0x44f04000 /* 000113c1 - 000113c1 [ 1] */, + 0x44f0c001 /* 000113c3 - 000113c4 [ 2] */, + 0x44f18000 /* 000113c6 - 000113c6 [ 1] */, + 0x44f2c000 /* 000113cb - 000113cb [ 1] */, + 0x44f58000 /* 000113d6 - 000113d6 [ 1] */, + 0x44f64007 /* 000113d9 - 000113e0 [ 8] */, + 0x44f8c01c /* 000113e3 - 000113ff [ 29] */, 0x45170000 /* 0001145c - 0001145c [ 1] */, 0x4518801d /* 00011462 - 0001147f [ 30] */, 0x45320007 /* 000114c8 - 000114cf [ 8] */, @@ -589,7 +604,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x45968005 /* 0001165a - 0001165f [ 6] */, 0x459b4012 /* 0001166d - 0001167f [ 19] */, 0x45ae8005 /* 000116ba - 000116bf [ 6] */, - 0x45b28035 /* 000116ca - 000116ff [ 54] */, + 0x45b28005 /* 000116ca - 000116cf [ 6] */, + 0x45b9001b /* 000116e4 - 000116ff [ 28] */, 0x45c6c001 /* 0001171b - 0001171c [ 2] */, 0x45cb0003 /* 0001172c - 0001172f [ 4] */, 0x45d1c0b8 /* 00011747 - 000117ff [ 185] */, @@ -609,7 +625,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x46920007 /* 00011a48 - 00011a4f [ 8] */, 0x46a8c00c /* 00011aa3 - 00011aaf [ 13] */, 0x46be4006 /* 00011af9 - 00011aff [ 7] */, - 0x46c280f5 /* 00011b0a - 00011bff [ 246] */, + 0x46c280b5 /* 00011b0a - 00011bbf [ 182] */, + 0x46f8800d /* 00011be2 - 00011bef [ 14] */, + 0x46fe8005 /* 00011bfa - 00011bff [ 6] */, 0x47024000 /* 00011c09 - 00011c09 [ 1] */, 0x470dc000 /* 00011c37 - 00011c37 [ 1] */, 0x47118009 /* 00011c46 - 00011c4f [ 10] */, @@ -633,7 +651,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x47be4006 /* 00011ef9 - 00011eff [ 7] */, 0x47c44000 /* 00011f11 - 00011f11 [ 1] */, 0x47cec002 /* 00011f3b - 00011f3d [ 3] */, - 0x47d68055 /* 00011f5a - 00011faf [ 86] */, + 0x47d6c054 /* 00011f5b - 00011faf [ 85] */, 0x47ec400e /* 00011fb1 - 00011fbf [ 15] */, 0x47fc800c /* 00011ff2 - 00011ffe [ 13] */, 0x48e68065 /* 0001239a - 000123ff [ 102] */, @@ -642,8 +660,10 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x49510a4b /* 00012544 - 00012f8f [ 2636] */, 0x4bfcc00c /* 00012ff3 - 00012fff [ 13] */, 0x4d0c000f /* 00013430 - 0001343f [ 16] */, - 0x4d158fa9 /* 00013456 - 000143ff [ 4010] */, - 0x5191e1b8 /* 00014647 - 000167ff [ 8633] */, + 0x4d158009 /* 00013456 - 0001345f [ 10] */, + 0x50fec004 /* 000143fb - 000143ff [ 5] */, + 0x5191dab8 /* 00014647 - 000160ff [ 6841] */, + 0x584e86c5 /* 0001613a - 000167ff [ 1734] */, 0x5a8e4006 /* 00016a39 - 00016a3f [ 7] */, 0x5a97c000 /* 00016a5f - 00016a5f [ 1] */, 0x5a9a8003 /* 00016a6a - 00016a6d [ 4] */, @@ -655,7 +675,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x5ad68000 /* 00016b5a - 00016b5a [ 1] */, 0x5ad88000 /* 00016b62 - 00016b62 [ 1] */, 0x5ade0004 /* 00016b78 - 00016b7c [ 5] */, - 0x5ae402af /* 00016b90 - 00016e3f [ 688] */, + 0x5ae401af /* 00016b90 - 00016d3f [ 432] */, + 0x5b5e80c5 /* 00016d7a - 00016e3f [ 198] */, 0x5ba6c064 /* 00016e9b - 00016eff [ 101] */, 0x5bd2c003 /* 00016f4b - 00016f4e [ 4] */, 0x5be20006 /* 00016f88 - 00016f8e [ 7] */, @@ -663,7 +684,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x5bf9400a /* 00016fe5 - 00016fef [ 11] */, 0x5bfc800d /* 00016ff2 - 00016fff [ 14] */, 0x61fe0007 /* 000187f8 - 000187ff [ 8] */, - 0x63358029 /* 00018cd6 - 00018cff [ 42] */, + 0x63358028 /* 00018cd6 - 00018cfe [ 41] */, 0x634262e6 /* 00018d09 - 0001afef [ 8935] */, 0x6bfd0000 /* 0001aff4 - 0001aff4 [ 1] */, 0x6bff0000 /* 0001affc - 0001affc [ 1] */, @@ -678,7 +699,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x6f1f4002 /* 0001bc7d - 0001bc7f [ 3] */, 0x6f224006 /* 0001bc89 - 0001bc8f [ 7] */, 0x6f268001 /* 0001bc9a - 0001bc9b [ 2] */, - 0x6f28125f /* 0001bca0 - 0001ceff [ 4704] */, + 0x6f280f5f /* 0001bca0 - 0001cbff [ 3936] */, + 0x733e8005 /* 0001ccfa - 0001ccff [ 6] */, + 0x73ad004b /* 0001ceb4 - 0001ceff [ 76] */, 0x73cb8001 /* 0001cf2e - 0001cf2f [ 2] */, 0x73d1c008 /* 0001cf47 - 0001cf4f [ 9] */, 0x73f1003b /* 0001cfc4 - 0001cfff [ 60] */, @@ -730,7 +753,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x78abc010 /* 0001e2af - 0001e2bf [ 17] */, 0x78be8004 /* 0001e2fa - 0001e2fe [ 5] */, 0x78c001cf /* 0001e300 - 0001e4cf [ 464] */, - 0x793e82e5 /* 0001e4fa - 0001e7df [ 742] */, + 0x793e80d5 /* 0001e4fa - 0001e5cf [ 214] */, + 0x797ec003 /* 0001e5fb - 0001e5fe [ 4] */, + 0x798001df /* 0001e600 - 0001e7df [ 480] */, 0x79f9c000 /* 0001e7e7 - 0001e7e7 [ 1] */, 0x79fb0000 /* 0001e7ec - 0001e7ec [ 1] */, 0x79fbc000 /* 0001e7ef - 0001e7ef [ 1] */, @@ -800,18 +825,17 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x7e168005 /* 0001f85a - 0001f85f [ 6] */, 0x7e220007 /* 0001f888 - 0001f88f [ 8] */, 0x7e2b8001 /* 0001f8ae - 0001f8af [ 2] */, - 0x7e2c804d /* 0001f8b2 - 0001f8ff [ 78] */, + 0x7e2f0003 /* 0001f8bc - 0001f8bf [ 4] */, + 0x7e30803d /* 0001f8c2 - 0001f8ff [ 62] */, 0x7e95000b /* 0001fa54 - 0001fa5f [ 12] */, 0x7e9b8001 /* 0001fa6e - 0001fa6f [ 2] */, 0x7e9f4002 /* 0001fa7d - 0001fa7f [ 3] */, - 0x7ea24006 /* 0001fa89 - 0001fa8f [ 7] */, - 0x7eaf8000 /* 0001fabe - 0001fabe [ 1] */, - 0x7eb18007 /* 0001fac6 - 0001facd [ 8] */, - 0x7eb70003 /* 0001fadc - 0001fadf [ 4] */, - 0x7eba4006 /* 0001fae9 - 0001faef [ 7] */, + 0x7ea28004 /* 0001fa8a - 0001fa8e [ 5] */, + 0x7eb1c006 /* 0001fac7 - 0001facd [ 7] */, + 0x7eb74001 /* 0001fadd - 0001fade [ 2] */, + 0x7eba8005 /* 0001faea - 0001faef [ 6] */, 0x7ebe4006 /* 0001faf9 - 0001faff [ 7] */, 0x7ee4c000 /* 0001fb93 - 0001fb93 [ 1] */, - 0x7ef2c024 /* 0001fbcb - 0001fbef [ 37] */, 0x7efe8405 /* 0001fbfa - 0001ffff [ 1030] */, 0xa9b8001f /* 0002a6e0 - 0002a6ff [ 32] */, 0xadce8005 /* 0002b73a - 0002b73f [ 6] */, diff --git a/libcxx/include/__format/extended_grapheme_cluster_table.h b/libcxx/include/__format/extended_grapheme_cluster_table.h index 7653a9e03b815d..f76e018df7ae11 100644 --- a/libcxx/include/__format/extended_grapheme_cluster_table.h +++ b/libcxx/include/__format/extended_grapheme_cluster_table.h @@ -125,7 +125,7 @@ enum class __property : uint8_t { /// following benchmark. /// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp // clang-format off -_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1501] = { 0x00000091, 0x00005005, 0x00005811, @@ -164,7 +164,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x00414842, 0x0042c822, 0x00448018, - 0x0044c072, + 0x0044b882, 0x00465172, 0x00471008, 0x004719f2, @@ -246,14 +246,12 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0064101a, 0x0065e002, 0x0065f00a, - 0x0065f802, - 0x0066001a, + 0x0065f812, + 0x0066080a, 0x00661002, 0x0066181a, - 0x00663002, - 0x0066381a, - 0x0066501a, - 0x00666012, + 0x00663022, + 0x00665032, 0x0066a812, 0x00671012, 0x0067980a, @@ -318,10 +316,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x008b047c, 0x008d457b, 0x009ae822, - 0x00b89022, - 0x00b8a80a, - 0x00b99012, - 0x00b9a00a, + 0x00b89032, + 0x00b99022, 0x00ba9012, 0x00bb9012, 0x00bda012, @@ -361,29 +357,23 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x00d581e2, 0x00d80032, 0x00d8200a, - 0x00d9a062, - 0x00d9d80a, - 0x00d9e002, - 0x00d9e84a, - 0x00da1002, - 0x00da181a, + 0x00d9a092, + 0x00d9f03a, + 0x00da1022, 0x00db5882, 0x00dc0012, 0x00dc100a, 0x00dd080a, 0x00dd1032, 0x00dd301a, - 0x00dd4012, - 0x00dd500a, - 0x00dd5822, + 0x00dd4052, 0x00df3002, 0x00df380a, 0x00df4012, 0x00df502a, 0x00df6802, 0x00df700a, - 0x00df7822, - 0x00df901a, + 0x00df7842, 0x00e1207a, 0x00e16072, 0x00e1a01a, @@ -475,7 +465,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0547f802, 0x05493072, 0x054a38a2, - 0x054a901a, + 0x054a900a, + 0x054a9802, 0x054b01c4, 0x054c0022, 0x054c180a, @@ -484,7 +475,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x054db032, 0x054dd01a, 0x054de012, - 0x054df02a, + 0x054df01a, + 0x054e0002, 0x054f2802, 0x05514852, 0x0551781a, @@ -1328,8 +1320,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0851f802, 0x08572812, 0x08692032, + 0x086b4842, 0x08755812, - 0x0877e822, + 0x0877e032, 0x087a30a2, 0x087c1032, 0x0880000a, @@ -1357,7 +1350,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x088c100a, 0x088d982a, 0x088db082, - 0x088df81a, + 0x088df80a, + 0x088e0002, 0x088e1018, 0x088e4832, 0x088e700a, @@ -1365,9 +1359,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0891602a, 0x08917822, 0x0891901a, - 0x0891a002, - 0x0891a80a, - 0x0891b012, + 0x0891a032, 0x0891f002, 0x08920802, 0x0896f802, @@ -1381,11 +1373,24 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x089a0002, 0x089a083a, 0x089a381a, - 0x089a582a, + 0x089a581a, + 0x089a6802, 0x089ab802, 0x089b101a, 0x089b3062, 0x089b8042, + 0x089dc002, + 0x089dc81a, + 0x089dd852, + 0x089e1002, + 0x089e2802, + 0x089e3822, + 0x089e500a, + 0x089e601a, + 0x089e7022, + 0x089e8808, + 0x089e9002, + 0x089f0812, 0x08a1a82a, 0x08a1c072, 0x08a2001a, @@ -1422,10 +1427,10 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x08b5600a, 0x08b56802, 0x08b5701a, - 0x08b58052, - 0x08b5b00a, - 0x08b5b802, - 0x08b8e822, + 0x08b58072, + 0x08b8e802, + 0x08b8f00a, + 0x08b8f802, 0x08b91032, 0x08b9300a, 0x08b93842, @@ -1436,9 +1441,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x08c98002, 0x08c9884a, 0x08c9b81a, - 0x08c9d812, - 0x08c9e80a, - 0x08c9f002, + 0x08c9d832, 0x08c9f808, 0x08ca000a, 0x08ca0808, @@ -1495,28 +1498,29 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x08f9a01a, 0x08f9b042, 0x08f9f01a, - 0x08fa0002, - 0x08fa080a, - 0x08fa1002, + 0x08fa0022, + 0x08fad002, 0x09a180f1, 0x09a20002, 0x09a238e2, + 0x0b08f0b2, + 0x0b09502a, + 0x0b096822, 0x0b578042, 0x0b598062, + 0x0b6b180c, + 0x0b6b383c, 0x0b7a7802, 0x0b7a8b6a, 0x0b7c7832, 0x0b7f2002, - 0x0b7f801a, + 0x0b7f8012, 0x0de4e812, 0x0de50031, 0x0e7802d2, 0x0e798162, - 0x0e8b2802, - 0x0e8b300a, - 0x0e8b3822, - 0x0e8b680a, - 0x0e8b7042, + 0x0e8b2842, + 0x0e8b6852, 0x0e8b9871, 0x0e8bd872, 0x0e8c2862, @@ -1538,6 +1542,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0f157002, 0x0f176032, 0x0f276032, + 0x0f2f7012, 0x0f468062, 0x0f4a2062, 0x0f8007f3, diff --git a/libcxx/include/__format/indic_conjunct_break_table.h b/libcxx/include/__format/indic_conjunct_break_table.h index df6cfe6a02f348..f48ea625908e99 100644 --- a/libcxx/include/__format/indic_conjunct_break_table.h +++ b/libcxx/include/__format/indic_conjunct_break_table.h @@ -107,10 +107,9 @@ enum class __property : uint8_t { /// following benchmark. /// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp // clang-format off -_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { - 0x00180139, - 0x001a807d, - 0x00241811, +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[403] = { + 0x001801bd, + 0x00241819, 0x002c88b1, 0x002df801, 0x002e0805, @@ -125,6 +124,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { 0x0037500d, 0x00388801, 0x00398069, + 0x003d3029, 0x003f5821, 0x003fe801, 0x0040b00d, @@ -132,87 +132,174 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { 0x00412809, 0x00414811, 0x0042c809, - 0x0044c01d, + 0x0044b821, 0x0046505d, - 0x00471871, + 0x0047187d, 0x0048a890, + 0x0049d001, 0x0049e001, + 0x004a081d, 0x004a6802, - 0x004a880d, + 0x004a8819, 0x004ac01c, + 0x004b1005, 0x004bc01c, + 0x004c0801, 0x004ca84c, 0x004d5018, 0x004d9000, 0x004db00c, 0x004de001, + 0x004df001, + 0x004e080d, 0x004e6802, + 0x004eb801, 0x004ee004, 0x004ef800, + 0x004f1005, 0x004f8004, 0x004ff001, + 0x00500805, 0x0051e001, + 0x00520805, + 0x00523805, + 0x00525809, + 0x00528801, + 0x00538005, + 0x0053a801, + 0x00540805, 0x0054a84c, 0x00555018, 0x00559004, 0x0055a810, 0x0055e001, + 0x00560811, + 0x00563805, 0x00566802, + 0x00571005, 0x0057c800, + 0x0057d015, + 0x00580801, 0x0058a84c, 0x00595018, 0x00599004, 0x0059a810, 0x0059e001, + 0x0059f005, + 0x005a080d, 0x005a6802, + 0x005aa809, 0x005ae004, 0x005af800, + 0x005b1005, 0x005b8800, + 0x005c1001, + 0x005df001, + 0x005e0001, + 0x005e6801, + 0x005eb801, + 0x00600001, + 0x00... [truncated] ``````````
https://github.com/llvm/llvm-project/pull/125712 From libcxx-commits at lists.llvm.org Tue Feb 4 08:32:51 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Tue, 04 Feb 2025 08:32:51 -0800 (PST) Subject: [libcxx-commits] [libcxx] [lib++][Format] Updates Unicode database. (PR #125712) In-Reply-To: Message-ID: <67a24133.a70a0220.2cca19.020f@mx.google.com> github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning:
You can test this locally with the following command: ``````````bash git-clang-format --diff fe694b18dc518b86eae9aab85ff03abc54e1662f 9e2d61b91d3d04094e3a4b0bf68ce6e0d15283e0 --extensions h -- libcxx/include/__format/escaped_output_table.h libcxx/include/__format/extended_grapheme_cluster_table.h libcxx/include/__format/indic_conjunct_break_table.h libcxx/include/__format/width_estimation_table.h libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h ``````````
View the diff from clang-format here. ``````````diff diff --git a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h index 9664622ab4..20386ee553 100644 --- a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h +++ b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h @@ -82,8 +82,8 @@ struct data { }; /// The data for UTF-8. -std::array, 1093> data_utf8 = {{ - {"\U00000020\U00000020", {32, 32}, {1, 2}}, +std::array, 1093> data_utf8 = { + {{"\U00000020\U00000020", {32, 32}, {1, 2}}, {"\U00000020\U00000308\U00000020", {32, 32}, {3, 4}}, {"\U00000020\U0000000d", {32, 13}, {1, 2}}, {"\U00000020\U00000308\U0000000d", {32, 13}, {3, 4}}, @@ -1183,8 +1183,8 @@ std::array, 1093> data_utf8 = {{ /// since the size of the code units differ the breaks can contain different /// values. #ifndef TEST_HAS_NO_WIDE_CHARACTERS -std::array, 1093> data_utf16 = {{ - {L"\U00000020\U00000020", {32, 32}, {1, 2}}, +std::array, 1093> data_utf16 = { + {{L"\U00000020\U00000020", {32, 32}, {1, 2}}, {L"\U00000020\U00000308\U00000020", {32, 32}, {2, 3}}, {L"\U00000020\U0000000d", {32, 13}, {1, 2}}, {L"\U00000020\U00000308\U0000000d", {32, 13}, {2, 3}}, @@ -2283,8 +2283,8 @@ std::array, 1093> data_utf16 = {{ /// Note that most of the data for the UTF-16 and UTF-32 are identical. However /// since the size of the code units differ the breaks can contain different /// values. -std::array, 1093> data_utf32 = {{ - {L"\U00000020\U00000020", {32, 32}, {1, 2}}, +std::array, 1093> data_utf32 = { + {{L"\U00000020\U00000020", {32, 32}, {1, 2}}, {L"\U00000020\U00000308\U00000020", {32, 32}, {2, 3}}, {L"\U00000020\U0000000d", {32, 13}, {1, 2}}, {L"\U00000020\U00000308\U0000000d", {32, 13}, {2, 3}}, ``````````
https://github.com/llvm/llvm-project/pull/125712 From libcxx-commits at lists.llvm.org Tue Feb 4 08:56:35 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Tue, 04 Feb 2025 08:56:35 -0800 (PST) Subject: [libcxx-commits] [clang] [libcxx] Proxy ref (PR #125719) Message-ID: https://github.com/2LoS created https://github.com/llvm/llvm-project/pull/125719 Fixed `Reference`'s copy and move assignment operators >From 3109461716e5e78b23bea7a2eb6aac3d34348612 Mon Sep 17 00:00:00 2001 From: LoS Date: Mon, 13 Jan 2025 11:21:46 +0100 Subject: [PATCH 1/3] Fixed some warn-override tests in SemaCXX --- ...e => warn-inconsistent-missing-destructor-override.cpp} | 0 ...uctor-override => warn-suggest-destructor-override.cpp} | 0 .../{warn-suggest-override => warn-suggest-override.cpp} | 7 ++++--- 3 files changed, 4 insertions(+), 3 deletions(-) rename clang/test/SemaCXX/{warn-inconsistent-missing-destructor-override => warn-inconsistent-missing-destructor-override.cpp} (100%) rename clang/test/SemaCXX/{warn-suggest-destructor-override => warn-suggest-destructor-override.cpp} (100%) rename clang/test/SemaCXX/{warn-suggest-override => warn-suggest-override.cpp} (58%) diff --git a/clang/test/SemaCXX/warn-inconsistent-missing-destructor-override b/clang/test/SemaCXX/warn-inconsistent-missing-destructor-override.cpp similarity index 100% rename from clang/test/SemaCXX/warn-inconsistent-missing-destructor-override rename to clang/test/SemaCXX/warn-inconsistent-missing-destructor-override.cpp diff --git a/clang/test/SemaCXX/warn-suggest-destructor-override b/clang/test/SemaCXX/warn-suggest-destructor-override.cpp similarity index 100% rename from clang/test/SemaCXX/warn-suggest-destructor-override rename to clang/test/SemaCXX/warn-suggest-destructor-override.cpp diff --git a/clang/test/SemaCXX/warn-suggest-override b/clang/test/SemaCXX/warn-suggest-override.cpp similarity index 58% rename from clang/test/SemaCXX/warn-suggest-override rename to clang/test/SemaCXX/warn-suggest-override.cpp index e06c939ff001fc..436a17d489693c 100644 --- a/clang/test/SemaCXX/warn-suggest-override +++ b/clang/test/SemaCXX/warn-suggest-override.cpp @@ -17,13 +17,13 @@ struct C { struct D : public C { void run(); - // expected-warning at -1 {{'run()' overrides a member function but is not marked 'override'}} + // expected-warning at -1 {{'run' overrides a member function but is not marked 'override'}} ~D(); }; struct E : public C { virtual void run(); - // expected-warning at -1 {{'run()' overrides a member function but is not marked 'override'}} + // expected-warning at -1 {{'run' overrides a member function but is not marked 'override'}} virtual ~E(); }; @@ -32,7 +32,8 @@ struct F : public C { ~F() override; }; -struct G : public C { +struct G : public C { // expected-note {{mark 'G' as 'final'}} void run() final; ~G() final; + // expected-warning at -1 {{class with destructor marked as 'final' can not be inherited from}} }; >From edf5111da4d2b23b25c2902545517f3e3b5eb60c Mon Sep 17 00:00:00 2001 From: LoS Date: Mon, 13 Jan 2025 17:29:35 +0100 Subject: [PATCH 2/3] Cleaned types.pass.cpp tests for sequence containers (libcxx) --- .../containers/sequences/array/types.pass.cpp | 67 ++++++------- .../containers/sequences/deque/types.pass.cpp | 95 ++++++++---------- .../sequences/forwardlist/types.pass.cpp | 84 +++++++++------- .../containers/sequences/list/types.pass.cpp | 80 ++++++++------- .../sequences/vector.bool/types.pass.cpp | 60 ++++++------ .../sequences/vector/types.pass.cpp | 97 +++++++------------ 6 files changed, 229 insertions(+), 254 deletions(-) diff --git a/libcxx/test/std/containers/sequences/array/types.pass.cpp b/libcxx/test/std/containers/sequences/array/types.pass.cpp index c5098105079627..805d82d21ed09c 100644 --- a/libcxx/test/std/containers/sequences/array/types.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/types.pass.cpp @@ -28,12 +28,15 @@ #include #include +#include "../../Copyable.h" #include "test_macros.h" template -void test_iterators() { +void test_iterators() +{ typedef std::iterator_traits ItT; typedef std::iterator_traits CItT; + static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); @@ -47,48 +50,36 @@ void test_iterators() { static_assert((std::is_same::value), ""); } -int main(int, char**) +template +void test() { - { - typedef double T; - typedef std::array C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - test_iterators(); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same >::value), ""); + typedef std::array C; + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same >::value), ""); + static_assert((std::is_same >::value), ""); static_assert((std::is_signed::value), ""); static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } - { - typedef int* T; - typedef std::array C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); + test_iterators(); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same >::value), ""); +} - static_assert((std::is_signed::value), ""); - static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } +int main(int, char**) +{ + test(); + test(); + test(); + + test(); + test(); + test(); return 0; -} +} \ No newline at end of file diff --git a/libcxx/test/std/containers/sequences/deque/types.pass.cpp b/libcxx/test/std/containers/sequences/deque/types.pass.cpp index 8c14de0c77440a..1d1a5223ee6050 100644 --- a/libcxx/test/std/containers/sequences/deque/types.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/types.pass.cpp @@ -37,77 +37,58 @@ #include "../../Copyable.h" #include "min_allocator.h" +template +void test_iterators() +{ + typedef std::iterator_traits ItT; + typedef std::iterator_traits CItT; + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); +} + template -void -test() +void test() { typedef std::deque C; + typedef std::allocator_traits alloc_traits_t; static_assert((std::is_same::value), ""); - static_assert( - (std::is_same::value_type>::value), ""); static_assert((std::is_same::value), ""); - static_assert( - (std::is_same::size_type>::value), ""); - static_assert( - (std::is_same::difference_type>::value), - ""); - static_assert( - (std::is_same::value_type&>::value), ""); - static_assert((std::is_same::value_type&>::value), - ""); - static_assert((std::is_same::pointer>::value), ""); - static_assert( - (std::is_same::const_pointer>::value), ""); - static_assert((std::is_same< - typename std::iterator_traits::iterator_category, - std::random_access_iterator_tag>::value), ""); - static_assert((std::is_same< - typename std::iterator_traits::iterator_category, - std::random_access_iterator_tag>::value), ""); - static_assert((std::is_same< - typename C::reverse_iterator, - std::reverse_iterator >::value), ""); - static_assert((std::is_same< - typename C::const_reverse_iterator, - std::reverse_iterator >::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same >::value), ""); + static_assert((std::is_same >::value), ""); + static_assert((std::is_signed::value), ""); static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); + + test_iterators(); } int main(int, char**) { - test >(); - test >(); - test >(); - static_assert((std::is_same::allocator_type, - std::allocator >::value), ""); + test>(); + test>(); + test>(); #if TEST_STD_VER >= 11 - { - typedef std::deque> C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same>::value), ""); - static_assert((std::is_same>::value), ""); -// min_allocator doesn't have a size_type, so one gets synthesized - static_assert((std::is_same::type>::value), ""); - static_assert((std::is_same::value), ""); - - static_assert((std::is_signed::value), ""); - static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } + test>(); + test>(); + test>(); #endif return 0; diff --git a/libcxx/test/std/containers/sequences/forwardlist/types.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/types.pass.cpp index 116891d4980be9..891b0569d58add 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/types.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/types.pass.cpp @@ -30,6 +30,8 @@ #include #include "test_macros.h" +#include "test_allocator.h" +#include "../../Copyable.h" #include "min_allocator.h" // Ensures that we don't use a non-uglified name 'base' in the implementation of 'forward_list'. @@ -50,49 +52,57 @@ static_assert(std::is_same>::base, my_base>:: static_assert(std::is_same>::base, my_base>::value, ""); #endif -struct A { std::forward_list
v; }; // incomplete type support +template +void test_iterators() +{ + typedef std::iterator_traits ItT; + typedef std::iterator_traits CItT; -int main(int, char**) + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); +} + +template +void test() { - { - typedef std::forward_list C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); + typedef std::forward_list C; + typedef std::allocator_traits alloc_traits_t; - static_assert((std::is_signed::value), ""); - static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } -#if TEST_STD_VER >= 11 - { - typedef std::forward_list> C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same>::value), ""); - static_assert((std::is_same>::value), ""); -// min_allocator doesn't have a size_type, so one gets synthesized - static_assert((std::is_same::type>::value), ""); - static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); static_assert((std::is_signed::value), ""); static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } + + test_iterators(); +} + +int main(int, char**) +{ + test>(); + test>(); + test>(); + +#if TEST_STD_VER >= 11 + test>(); + test>(); + test>(); #endif return 0; -} +} \ No newline at end of file diff --git a/libcxx/test/std/containers/sequences/list/types.pass.cpp b/libcxx/test/std/containers/sequences/list/types.pass.cpp index a2d49080f1bcbb..5e8453b89d346b 100644 --- a/libcxx/test/std/containers/sequences/list/types.pass.cpp +++ b/libcxx/test/std/containers/sequences/list/types.pass.cpp @@ -27,6 +27,8 @@ #include #include "test_macros.h" +#include "test_allocator.h" +#include "../../Copyable.h" #include "min_allocator.h" // Ensures that we don't use a non-uglified name 'base' in the implementation of 'list'. @@ -47,47 +49,57 @@ static_assert(std::is_same>::base, my_base>:: static_assert(std::is_same>::base, my_base>::value, ""); #endif -struct A { std::list v; }; // incomplete type support +template +void test_iterators() +{ + typedef std::iterator_traits ItT; + typedef std::iterator_traits CItT; -int main(int, char**) + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); +} + +template +void test() { - { - typedef std::list C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same >::value_type&>::value), ""); - static_assert( - (std::is_same >::value_type&>::value), ""); - static_assert((std::is_same >::pointer>::value), ""); - static_assert( - (std::is_same >::const_pointer>::value), ""); + typedef std::list C; + typedef std::allocator_traits alloc_traits_t; + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same >::value), ""); + static_assert((std::is_same >::value), ""); static_assert((std::is_signed::value), ""); static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } -#if TEST_STD_VER >= 11 - { - typedef std::list> C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same>::value), ""); - static_assert((std::is_same>::value), ""); + test_iterators(); +} - static_assert((std::is_signed::value), ""); - static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } +int main(int, char**) +{ + test>(); + test>(); + test>(); + +#if TEST_STD_VER >= 11 + test>(); + test>(); + test>(); #endif return 0; -} +} \ No newline at end of file diff --git a/libcxx/test/std/containers/sequences/vector.bool/types.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/types.pass.cpp index d75d7151473521..9480b4f58198c4 100644 --- a/libcxx/test/std/containers/sequences/vector.bool/types.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/types.pass.cpp @@ -33,54 +33,58 @@ #include "test_macros.h" #include "test_allocator.h" -#include "../../Copyable.h" #include "min_allocator.h" +template +void test_iterators() +{ + typedef std::iterator_traits ItT; + typedef std::iterator_traits CItT; + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); +} + template -void -test() +void test() { typedef std::vector C; + typedef std::allocator_traits alloc_traits_t; static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); - static_assert((std::is_same::size_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same >::value), ""); + static_assert((std::is_same >::value), ""); static_assert((std::is_signed::value), ""); static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - - static_assert((std::is_same< - typename std::iterator_traits::iterator_category, - std::random_access_iterator_tag>::value), ""); - static_assert((std::is_same< - typename std::iterator_traits::iterator_category, - std::random_access_iterator_tag>::value), ""); - static_assert((std::is_same< - typename C::reverse_iterator, - std::reverse_iterator >::value), ""); - static_assert((std::is_same< - typename C::const_reverse_iterator, - std::reverse_iterator >::value), ""); + #if !defined(_LIBCPP_VERSION) || defined(_LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL) static_assert(std::is_same::value, ""); #endif + + test_iterators(); } int main(int, char**) { - test >(); - test >(); - static_assert((std::is_same::allocator_type, - std::allocator >::value), ""); + test>(); + #if TEST_STD_VER >= 11 - test >(); + test>(); #endif return 0; -} +} \ No newline at end of file diff --git a/libcxx/test/std/containers/sequences/vector/types.pass.cpp b/libcxx/test/std/containers/sequences/vector/types.pass.cpp index f4d7fa088842fc..db11404bb58d5b 100644 --- a/libcxx/test/std/containers/sequences/vector/types.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/types.pass.cpp @@ -37,82 +37,59 @@ #include "../../Copyable.h" #include "min_allocator.h" -struct A { std::vector v; }; // incomplete type support +template +void test_iterators() +{ + typedef std::iterator_traits ItT; + typedef std::iterator_traits CItT; + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); +} template -void -test() +void test() { typedef std::vector C; + typedef std::allocator_traits alloc_traits_t; -// TODO: These tests should use allocator_traits to get stuff, rather than -// blindly pulling typedefs out of the allocator. This is why we can't call -// test>() below. static_assert((std::is_same::value), ""); - static_assert( - (std::is_same::value_type>::value), ""); static_assert((std::is_same::value), ""); - static_assert( - (std::is_same::size_type>::value), ""); - static_assert( - (std::is_same::difference_type>::value), - ""); - static_assert( - (std::is_same::value_type&>::value), ""); - static_assert((std::is_same::value_type&>::value), - ""); - static_assert((std::is_same::pointer>::value), ""); - static_assert( - (std::is_same::const_pointer>::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same >::value), ""); + static_assert((std::is_same >::value), ""); static_assert((std::is_signed::value), ""); static_assert((std::is_unsigned::value), ""); -// static_assert((std::is_same::difference_type>::value), ""); -// static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same< - typename std::iterator_traits::iterator_category, - std::random_access_iterator_tag>::value), ""); - static_assert((std::is_same< - typename std::iterator_traits::iterator_category, - std::random_access_iterator_tag>::value), ""); - static_assert((std::is_same< - typename C::reverse_iterator, - std::reverse_iterator >::value), ""); - static_assert((std::is_same< - typename C::const_reverse_iterator, - std::reverse_iterator >::value), ""); + test_iterators(); } int main(int, char**) { - test >(); - test >(); - test >(); - static_assert((std::is_same::allocator_type, - std::allocator >::value), ""); -#if TEST_STD_VER >= 11 - { + test>(); + test>(); + test>(); - typedef std::vector > C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same>::value), ""); - static_assert((std::is_same>::value), ""); - - static_assert((std::is_signed::value), ""); - static_assert((std::is_unsigned::value), ""); -// static_assert((std::is_same::difference_type>::value), ""); -// static_assert((std::is_same::difference_type>::value), ""); - } +#if TEST_STD_VER >= 11 + test>(); + test>(); + test>(); #endif return 0; -} +} \ No newline at end of file >From 8cc7463312f6aa786482e34530ea36cc77762cfb Mon Sep 17 00:00:00 2001 From: LoS Date: Tue, 4 Feb 2025 17:58:22 +0100 Subject: [PATCH 3/3] Fixed the 's copy and move assignment operators --- .../robust_against_proxy_iterators_lifetime_bugs.pass.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp index c89d6f5a229e8a..e39881a5e5a3ba 100644 --- a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp +++ b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp @@ -159,7 +159,7 @@ class LifetimeIterator { assert(!rhs.moved_from_); rhs.moved_from_ = true; - *v_ = *rhs.v_; + *v_ = std::move(*rhs.v_); moved_from_ = false; return *this; @@ -368,7 +368,7 @@ class ConstexprIterator { constexpr Reference(const Reference& rhs) = default; constexpr Reference& operator=(const Reference& rhs) { assert(!rhs.moved_from_); - v_ = rhs.v_; + *v_ = *rhs.v_; moved_from_ = false; return *this; @@ -384,7 +384,7 @@ class ConstexprIterator { rhs.moved_from_ = true; moved_from_ = false; - v_ = rhs.v_; + *v_ = std::move(*rhs.v_); return *this; } From libcxx-commits at lists.llvm.org Tue Feb 4 08:57:27 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Tue, 04 Feb 2025 08:57:27 -0800 (PST) Subject: [libcxx-commits] [clang] [libcxx] Proxy ref (PR #125719) In-Reply-To: Message-ID: <67a246f7.170a0220.31619f.dc67@mx.google.com> https://github.com/2LoS closed https://github.com/llvm/llvm-project/pull/125719 From libcxx-commits at lists.llvm.org Tue Feb 4 08:58:50 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Tue, 04 Feb 2025 08:58:50 -0800 (PST) Subject: [libcxx-commits] [clang] [libcxx] Proxy ref (PR #125719) In-Reply-To: Message-ID: <67a2474a.170a0220.1ac22f.d212@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-clang Author: LoS (2LoS)
Changes Fixed `Reference`'s copy and move assignment operators --- Patch is 36.65 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/125719.diff 10 Files Affected: - (renamed) clang/test/SemaCXX/warn-inconsistent-missing-destructor-override.cpp () - (renamed) clang/test/SemaCXX/warn-suggest-destructor-override.cpp () - (renamed) clang/test/SemaCXX/warn-suggest-override.cpp (+4-3) - (modified) libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp (+3-3) - (modified) libcxx/test/std/containers/sequences/array/types.pass.cpp (+29-38) - (modified) libcxx/test/std/containers/sequences/deque/types.pass.cpp (+38-57) - (modified) libcxx/test/std/containers/sequences/forwardlist/types.pass.cpp (+47-37) - (modified) libcxx/test/std/containers/sequences/list/types.pass.cpp (+46-34) - (modified) libcxx/test/std/containers/sequences/vector.bool/types.pass.cpp (+32-28) - (modified) libcxx/test/std/containers/sequences/vector/types.pass.cpp (+37-60) ``````````diff diff --git a/clang/test/SemaCXX/warn-inconsistent-missing-destructor-override b/clang/test/SemaCXX/warn-inconsistent-missing-destructor-override.cpp similarity index 100% rename from clang/test/SemaCXX/warn-inconsistent-missing-destructor-override rename to clang/test/SemaCXX/warn-inconsistent-missing-destructor-override.cpp diff --git a/clang/test/SemaCXX/warn-suggest-destructor-override b/clang/test/SemaCXX/warn-suggest-destructor-override.cpp similarity index 100% rename from clang/test/SemaCXX/warn-suggest-destructor-override rename to clang/test/SemaCXX/warn-suggest-destructor-override.cpp diff --git a/clang/test/SemaCXX/warn-suggest-override b/clang/test/SemaCXX/warn-suggest-override.cpp similarity index 58% rename from clang/test/SemaCXX/warn-suggest-override rename to clang/test/SemaCXX/warn-suggest-override.cpp index e06c939ff001fc9..436a17d489693c3 100644 --- a/clang/test/SemaCXX/warn-suggest-override +++ b/clang/test/SemaCXX/warn-suggest-override.cpp @@ -17,13 +17,13 @@ struct C { struct D : public C { void run(); - // expected-warning at -1 {{'run()' overrides a member function but is not marked 'override'}} + // expected-warning at -1 {{'run' overrides a member function but is not marked 'override'}} ~D(); }; struct E : public C { virtual void run(); - // expected-warning at -1 {{'run()' overrides a member function but is not marked 'override'}} + // expected-warning at -1 {{'run' overrides a member function but is not marked 'override'}} virtual ~E(); }; @@ -32,7 +32,8 @@ struct F : public C { ~F() override; }; -struct G : public C { +struct G : public C { // expected-note {{mark 'G' as 'final'}} void run() final; ~G() final; + // expected-warning at -1 {{class with destructor marked as 'final' can not be inherited from}} }; diff --git a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp index c89d6f5a229e8ad..e39881a5e5a3ba1 100644 --- a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp +++ b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp @@ -159,7 +159,7 @@ class LifetimeIterator { assert(!rhs.moved_from_); rhs.moved_from_ = true; - *v_ = *rhs.v_; + *v_ = std::move(*rhs.v_); moved_from_ = false; return *this; @@ -368,7 +368,7 @@ class ConstexprIterator { constexpr Reference(const Reference& rhs) = default; constexpr Reference& operator=(const Reference& rhs) { assert(!rhs.moved_from_); - v_ = rhs.v_; + *v_ = *rhs.v_; moved_from_ = false; return *this; @@ -384,7 +384,7 @@ class ConstexprIterator { rhs.moved_from_ = true; moved_from_ = false; - v_ = rhs.v_; + *v_ = std::move(*rhs.v_); return *this; } diff --git a/libcxx/test/std/containers/sequences/array/types.pass.cpp b/libcxx/test/std/containers/sequences/array/types.pass.cpp index c50981050796275..805d82d21ed09c8 100644 --- a/libcxx/test/std/containers/sequences/array/types.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/types.pass.cpp @@ -28,12 +28,15 @@ #include #include +#include "../../Copyable.h" #include "test_macros.h" template -void test_iterators() { +void test_iterators() +{ typedef std::iterator_traits ItT; typedef std::iterator_traits CItT; + static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); @@ -47,48 +50,36 @@ void test_iterators() { static_assert((std::is_same::value), ""); } -int main(int, char**) +template +void test() { - { - typedef double T; - typedef std::array C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - test_iterators(); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same >::value), ""); + typedef std::array C; + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same >::value), ""); + static_assert((std::is_same >::value), ""); static_assert((std::is_signed::value), ""); static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } - { - typedef int* T; - typedef std::array C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); + test_iterators(); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same >::value), ""); +} - static_assert((std::is_signed::value), ""); - static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } +int main(int, char**) +{ + test(); + test(); + test(); + + test(); + test(); + test(); return 0; -} +} \ No newline at end of file diff --git a/libcxx/test/std/containers/sequences/deque/types.pass.cpp b/libcxx/test/std/containers/sequences/deque/types.pass.cpp index 8c14de0c77440a5..1d1a5223ee6050a 100644 --- a/libcxx/test/std/containers/sequences/deque/types.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/types.pass.cpp @@ -37,77 +37,58 @@ #include "../../Copyable.h" #include "min_allocator.h" +template +void test_iterators() +{ + typedef std::iterator_traits ItT; + typedef std::iterator_traits CItT; + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); +} + template -void -test() +void test() { typedef std::deque C; + typedef std::allocator_traits alloc_traits_t; static_assert((std::is_same::value), ""); - static_assert( - (std::is_same::value_type>::value), ""); static_assert((std::is_same::value), ""); - static_assert( - (std::is_same::size_type>::value), ""); - static_assert( - (std::is_same::difference_type>::value), - ""); - static_assert( - (std::is_same::value_type&>::value), ""); - static_assert((std::is_same::value_type&>::value), - ""); - static_assert((std::is_same::pointer>::value), ""); - static_assert( - (std::is_same::const_pointer>::value), ""); - static_assert((std::is_same< - typename std::iterator_traits::iterator_category, - std::random_access_iterator_tag>::value), ""); - static_assert((std::is_same< - typename std::iterator_traits::iterator_category, - std::random_access_iterator_tag>::value), ""); - static_assert((std::is_same< - typename C::reverse_iterator, - std::reverse_iterator >::value), ""); - static_assert((std::is_same< - typename C::const_reverse_iterator, - std::reverse_iterator >::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same >::value), ""); + static_assert((std::is_same >::value), ""); + static_assert((std::is_signed::value), ""); static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); + + test_iterators(); } int main(int, char**) { - test >(); - test >(); - test >(); - static_assert((std::is_same::allocator_type, - std::allocator >::value), ""); + test>(); + test>(); + test>(); #if TEST_STD_VER >= 11 - { - typedef std::deque> C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same>::value), ""); - static_assert((std::is_same>::value), ""); -// min_allocator doesn't have a size_type, so one gets synthesized - static_assert((std::is_same::type>::value), ""); - static_assert((std::is_same::value), ""); - - static_assert((std::is_signed::value), ""); - static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } + test>(); + test>(); + test>(); #endif return 0; diff --git a/libcxx/test/std/containers/sequences/forwardlist/types.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/types.pass.cpp index 116891d4980be9c..891b0569d58add3 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/types.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/types.pass.cpp @@ -30,6 +30,8 @@ #include #include "test_macros.h" +#include "test_allocator.h" +#include "../../Copyable.h" #include "min_allocator.h" // Ensures that we don't use a non-uglified name 'base' in the implementation of 'forward_list'. @@ -50,49 +52,57 @@ static_assert(std::is_same>::base, my_base>:: static_assert(std::is_same>::base, my_base>::value, ""); #endif -struct A { std::forward_list v; }; // incomplete type support +template +void test_iterators() +{ + typedef std::iterator_traits ItT; + typedef std::iterator_traits CItT; -int main(int, char**) + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); +} + +template +void test() { - { - typedef std::forward_list C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); + typedef std::forward_list C; + typedef std::allocator_traits alloc_traits_t; - static_assert((std::is_signed::value), ""); - static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } -#if TEST_STD_VER >= 11 - { - typedef std::forward_list> C; - static_assert((std::is_same::value), ""); - static_assert((std::is_same >::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same>::value), ""); - static_assert((std::is_same>::value), ""); -// min_allocator doesn't have a size_type, so one gets synthesized - static_assert((std::is_same::type>::value), ""); - static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); static_assert((std::is_signed::value), ""); static_assert((std::is_unsigned::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - static_assert((std::is_same::difference_type>::value), ""); - } + + test_iterators(); +} + +int main(int, char**) +{ + test>(); + test>(); + test>(); + +#if TEST_STD_VER >= 11 + test>(); + test>(); + test>(); #endif return 0; -} +} \ No newline at end of file diff --git a/libcxx/test/std/containers... [truncated] ``````````
https://github.com/llvm/llvm-project/pull/125719 From libcxx-commits at lists.llvm.org Tue Feb 4 09:09:02 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 09:09:02 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) In-Reply-To: Message-ID: <67a249ae.170a0220.2d3217.d62f@mx.google.com> https://github.com/ldionne edited https://github.com/llvm/llvm-project/pull/125550 From libcxx-commits at lists.llvm.org Tue Feb 4 09:09:02 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 09:09:02 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) In-Reply-To: Message-ID: <67a249ae.a70a0220.30f985.06ba@mx.google.com> https://github.com/ldionne approved this pull request. This LGTM with minor comments applied. https://github.com/llvm/llvm-project/pull/125550 From libcxx-commits at lists.llvm.org Tue Feb 4 09:09:03 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 09:09:03 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) In-Reply-To: Message-ID: <67a249af.170a0220.10f83b.e2b4@mx.google.com> ================ @@ -0,0 +1,159 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// +// +// class tai_clock; + +// static tai_time> +// from_utc(const utc<_Duration>& __time) noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "assert_macros.h" +#include "concat_macros.h" + +static void test_known_values() { + namespace cr = std::chrono; + using namespace std::literals::chrono_literals; + constexpr auto unix_to_tai_epoch_offset = cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + + // [time.clock.tai.overview]/1 + // ... 1958-01-01 00:00:00 TAI is equivalent to 1957-12-31 23:59:50 UTC + // ... 2000-01-01 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI + + assert(cr::tai_clock::from_utc(cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 1958} - 10s)) == + cr::tai_seconds{0s}); + + assert(cr::tai_clock::from_utc(cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 2000})) == + cr::tai_seconds{(cr::sys_days{cr::January / 1 / 2000} + unix_to_tai_epoch_offset).time_since_epoch()} + 32s); +} + +template +static void test_leap_seconds(std::chrono::utc_time utc, + std::chrono::tai_time expected, + std::source_location loc = std::source_location::current()) { + auto tai = std::chrono::tai_clock::from_utc(utc); + TEST_REQUIRE(tai == expected, + TEST_WRITE_CONCATENATED(loc, "\nExpected output ", expected, "\nActual output ", tai, '\n')); +} + +// Tests set if existing database entries at the time of writing. +static void test_transitions() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + // "sys" is the time of the transition to the next leap second. + // "elapsed" is the number of leap seconds before the transition. + auto test_transition = [](cr::sys_days sys, cr::seconds elapsed) { + constexpr auto unix_to_tai_epoch_offset = + cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + cr::tai_seconds tai{sys.time_since_epoch() + unix_to_tai_epoch_offset + elapsed}; + + test_leap_seconds(cr::utc_clock::from_sys(sys - 1ns), tai - 1ns); + test_leap_seconds(cr::utc_clock::from_sys(sys), tai + 1s); + test_leap_seconds(cr::utc_clock::from_sys(sys) + 1ns, tai + 1s + 1ns); + }; + + // Transitions from the start of UTC. + test_transition(cr::sys_days{cr::July / 1 / 1972}, 10s); + test_transition(cr::sys_days{cr::January / 1 / 1973}, 11s); + test_transition(cr::sys_days{cr::January / 1 / 1974}, 12s); + test_transition(cr::sys_days{cr::January / 1 / 1975}, 13s); + test_transition(cr::sys_days{cr::January / 1 / 1976}, 14s); + test_transition(cr::sys_days{cr::January / 1 / 1977}, 15s); + test_transition(cr::sys_days{cr::January / 1 / 1978}, 16s); + test_transition(cr::sys_days{cr::January / 1 / 1979}, 17s); + test_transition(cr::sys_days{cr::January / 1 / 1980}, 18s); + test_transition(cr::sys_days{cr::July / 1 / 1981}, 19s); + test_transition(cr::sys_days{cr::July / 1 / 1982}, 20s); + test_transition(cr::sys_days{cr::July / 1 / 1983}, 21s); + test_transition(cr::sys_days{cr::July / 1 / 1985}, 22s); + test_transition(cr::sys_days{cr::January / 1 / 1988}, 23s); + test_transition(cr::sys_days{cr::January / 1 / 1990}, 24s); + test_transition(cr::sys_days{cr::January / 1 / 1991}, 25s); + test_transition(cr::sys_days{cr::July / 1 / 1992}, 26s); + test_transition(cr::sys_days{cr::July / 1 / 1993}, 27s); + test_transition(cr::sys_days{cr::July / 1 / 1994}, 28s); + test_transition(cr::sys_days{cr::January / 1 / 1996}, 29s); + test_transition(cr::sys_days{cr::July / 1 / 1997}, 30s); + test_transition(cr::sys_days{cr::January / 1 / 1999}, 31s); + test_transition(cr::sys_days{cr::January / 1 / 2006}, 32s); + test_transition(cr::sys_days{cr::January / 1 / 2009}, 33s); + test_transition(cr::sys_days{cr::July / 1 / 2012}, 34s); + test_transition(cr::sys_days{cr::July / 1 / 2015}, 35s); + test_transition(cr::sys_days{cr::January / 1 / 2017}, 36s); +} + +// Tests whether the return type is the expected type. +static void test_return_type() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0ns}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0us}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0ms}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::seconds{0}}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::minutes{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::hours{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::days{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::weeks{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::months{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::years{0}}); + } +} + +int main(int, const char**) { + using namespace std::literals::chrono_literals; + std::chrono::utc_seconds time = std::chrono::utc_seconds{0s}; + static_assert(noexcept(std::chrono::tai_clock::from_utc(time))); + + test_known_values(); + test_transitions(); + test_return_type(); ---------------- ldionne wrote: `return 0` (also below) https://github.com/llvm/llvm-project/pull/125550 From libcxx-commits at lists.llvm.org Tue Feb 4 09:09:03 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 09:09:03 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) In-Reply-To: Message-ID: <67a249af.a70a0220.72749.2146@mx.google.com> ================ @@ -0,0 +1,164 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb +// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME + +// TODO FMT This test should not require std::to_chars(floating-point) +// XFAIL: availability-fp_to_chars-missing + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// REQUIRES: locale.fr_FR.UTF-8 +// REQUIRES: locale.ja_JP.UTF-8 + +// + +// class taitem_clock; ---------------- ldionne wrote: ```suggestion // class tai_clock; ``` https://github.com/llvm/llvm-project/pull/125550 From libcxx-commits at lists.llvm.org Tue Feb 4 09:09:03 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 09:09:03 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) In-Reply-To: Message-ID: <67a249af.630a0220.181d12.1a77@mx.google.com> ================ @@ -0,0 +1,99 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_TAI_CLOCK_H +#define _LIBCPP___CHRONO_TAI_CLOCK_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if _LIBCPP_HAS_EXPERIMENTAL_TZDB + +# include <__assert> +# include <__chrono/duration.h> +# include <__chrono/time_point.h> +# include <__chrono/utc_clock.h> +# include <__config> +# include <__type_traits/common_type.h> + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION + +namespace chrono { + +class tai_clock; + +template +using tai_time = time_point; +using tai_seconds = tai_time; + +// [time.clock.tai.overview]/1 +// The clock tai_clock measures seconds since 1958-01-01 00:00:00 and is +// offset 10s ahead of UTC at this date. That is, 1958-01-01 00:00:00 TAI is +// equivalent to 1957-12-31 23:59:50 UTC. Leap seconds are not inserted into +// TAI. Therefore every time a leap second is inserted into UTC, UTC shifts +// another second with respect to TAI. For example by 2000-01-01 there had +// been 22 positive and 0 negative leap seconds inserted so 2000-01-01 +// 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI (22s plus the +// initial 10s offset). +// +// Note this does not specify what the UTC offset before 1958-01-01 00:00:00 +// TAI is. However the member functions are fully specified in the standard. +// https://koka-lang.github.io/koka/doc/std_time_utc.html contains more +// information and references. ---------------- ldionne wrote: ```suggestion // Note this does not specify what the UTC offset before 1958-01-01 00:00:00 // TAI is, nor does it follow the "real" TAI clock between 1958-01-01 and the // start of the UTC epoch. So while the member functions are fully specified in // the standard, they do not technically follow the "real-world" TAI clock with // 100% accuracy. // // https://koka-lang.github.io/koka/doc/std_time_utc.html contains more // information and references. ``` https://github.com/llvm/llvm-project/pull/125550 From libcxx-commits at lists.llvm.org Tue Feb 4 09:09:04 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 09:09:04 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) In-Reply-To: Message-ID: <67a249b0.630a0220.1cbccc.f5f4@mx.google.com> ================ @@ -11,6 +11,7 @@ #include #include +#include ---------------- ldionne wrote: This is C++20 only, this might require a `TEST_STD_VER` check. https://github.com/llvm/llvm-project/pull/125550 From libcxx-commits at lists.llvm.org Tue Feb 4 09:09:04 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 09:09:04 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) In-Reply-To: Message-ID: <67a249b0.170a0220.3ad322.ddc1@mx.google.com> ================ @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb ---------------- ldionne wrote: It probably makes sense to only use `UNSUPPORTED: no-tzdb` here. The `tzdb` feature should probably depend on the `filesystem` feature. https://github.com/llvm/llvm-project/pull/125550 From libcxx-commits at lists.llvm.org Tue Feb 4 09:13:14 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 09:13:14 -0800 (PST) Subject: [libcxx-commits] [libcxx] [lib++][Format] Updates Unicode database. (PR #125712) In-Reply-To: Message-ID: <67a24aaa.170a0220.1ceef0.e734@mx.google.com> https://github.com/ldionne approved this pull request. https://github.com/llvm/llvm-project/pull/125712 From libcxx-commits at lists.llvm.org Tue Feb 4 09:16:12 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Tue, 04 Feb 2025 09:16:12 -0800 (PST) Subject: [libcxx-commits] [libcxx] Fixed Reference copy and move assignment operators (PR #125723) Message-ID: https://github.com/2LoS created https://github.com/llvm/llvm-project/pull/125723 None >From fb9032fa397b399affb27757e67f85d30b2ace65 Mon Sep 17 00:00:00 2001 From: LoS Date: Tue, 4 Feb 2025 18:21:30 +0100 Subject: [PATCH] Fixed Reference copy and move assignment operators --- .../robust_against_proxy_iterators_lifetime_bugs.pass.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp index c89d6f5a229e8ad..e39881a5e5a3ba1 100644 --- a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp +++ b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp @@ -159,7 +159,7 @@ class LifetimeIterator { assert(!rhs.moved_from_); rhs.moved_from_ = true; - *v_ = *rhs.v_; + *v_ = std::move(*rhs.v_); moved_from_ = false; return *this; @@ -368,7 +368,7 @@ class ConstexprIterator { constexpr Reference(const Reference& rhs) = default; constexpr Reference& operator=(const Reference& rhs) { assert(!rhs.moved_from_); - v_ = rhs.v_; + *v_ = *rhs.v_; moved_from_ = false; return *this; @@ -384,7 +384,7 @@ class ConstexprIterator { rhs.moved_from_ = true; moved_from_ = false; - v_ = rhs.v_; + *v_ = std::move(*rhs.v_); return *this; } From libcxx-commits at lists.llvm.org Tue Feb 4 09:18:59 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Tue, 04 Feb 2025 09:18:59 -0800 (PST) Subject: [libcxx-commits] [libcxx] Fixed Reference copy and move assignment operators (PR #125723) In-Reply-To: Message-ID: <67a24c03.170a0220.115382.adde@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-libcxx Author: LoS (2LoS)
Changes --- Full diff: https://github.com/llvm/llvm-project/pull/125723.diff 1 Files Affected: - (modified) libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp (+3-3) ``````````diff diff --git a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp index c89d6f5a229e8a..e39881a5e5a3ba 100644 --- a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp +++ b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp @@ -159,7 +159,7 @@ class LifetimeIterator { assert(!rhs.moved_from_); rhs.moved_from_ = true; - *v_ = *rhs.v_; + *v_ = std::move(*rhs.v_); moved_from_ = false; return *this; @@ -368,7 +368,7 @@ class ConstexprIterator { constexpr Reference(const Reference& rhs) = default; constexpr Reference& operator=(const Reference& rhs) { assert(!rhs.moved_from_); - v_ = rhs.v_; + *v_ = *rhs.v_; moved_from_ = false; return *this; @@ -384,7 +384,7 @@ class ConstexprIterator { rhs.moved_from_ = true; moved_from_ = false; - v_ = rhs.v_; + *v_ = std::move(*rhs.v_); return *this; } ``````````
https://github.com/llvm/llvm-project/pull/125723 From libcxx-commits at lists.llvm.org Tue Feb 4 09:21:24 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Tue, 04 Feb 2025 09:21:24 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][TZDB] Fixes %z escaping. (PR #125399) In-Reply-To: Message-ID: <67a24c94.050a0220.3c3719.2b7b@mx.google.com> mordante wrote: /cherry-pick a27f3b2 https://github.com/llvm/llvm-project/pull/125399 From libcxx-commits at lists.llvm.org Tue Feb 4 09:25:17 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Tue, 04 Feb 2025 09:25:17 -0800 (PST) Subject: [libcxx-commits] [libcxx] Fixed Reference copy and move assignment operators (PR #125723) In-Reply-To: Message-ID: <67a24d7d.170a0220.265463.d6f0@mx.google.com> github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning:
You can test this locally with the following command: ``````````bash git-clang-format --diff 906eeeda833b30fb7fdc3b7586de34b65d575b45 fb9032fa397b399affb27757e67f85d30b2ace65 --extensions cpp -- libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp ``````````
View the diff from clang-format here. ``````````diff diff --git a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp index e39881a5e5..4b5b7d31b7 100644 --- a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp +++ b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp @@ -159,7 +159,7 @@ class LifetimeIterator { assert(!rhs.moved_from_); rhs.moved_from_ = true; - *v_ = std::move(*rhs.v_); + *v_ = std::move(*rhs.v_); moved_from_ = false; return *this; @@ -368,7 +368,7 @@ class ConstexprIterator { constexpr Reference(const Reference& rhs) = default; constexpr Reference& operator=(const Reference& rhs) { assert(!rhs.moved_from_); - *v_ = *rhs.v_; + *v_ = *rhs.v_; moved_from_ = false; return *this; ``````````
https://github.com/llvm/llvm-project/pull/125723 From libcxx-commits at lists.llvm.org Tue Feb 4 09:26:17 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Tue, 04 Feb 2025 09:26:17 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) In-Reply-To: Message-ID: <67a24db9.050a0220.18bcff.f0ea@mx.google.com> ================ @@ -11,6 +11,7 @@ #include #include +#include ---------------- mordante wrote: Actually the file already is mostly C++20, so the check is already there. https://github.com/llvm/llvm-project/pull/125550 From libcxx-commits at lists.llvm.org Tue Feb 4 09:54:27 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Tue, 04 Feb 2025 09:54:27 -0800 (PST) Subject: [libcxx-commits] [libcxx] [lib++][Format] Updates Unicode database. (PR #125712) In-Reply-To: Message-ID: <67a25453.170a0220.322f19.4697@mx.google.com> https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/125712 >From 04fc5782a5bf720d04c12bd340ff0efa5b0a5845 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Mon, 3 Feb 2025 22:51:36 +0100 Subject: [PATCH] [lib++][Format] Updates Unicode database. Updates the databease to the Unicode release 16.0.0. The algorithms of the Grapheme clustering rules have not changed. --- libcxx/docs/ReleaseNotes/21.rst | 1 + .../include/__format/escaped_output_table.h | 82 +- .../extended_grapheme_cluster_table.h | 99 +- .../__format/indic_conjunct_break_table.h | 312 +++- .../include/__format/width_estimation_table.h | 19 +- .../format.string.std/escaped_output.pass.cpp | 2 +- .../extended_grapheme_cluster.h | 1344 +++++++---------- .../extended_grapheme_cluster.pass.cpp | 10 +- .../data/unicode/DerivedCoreProperties.txt | 834 ++++++++-- .../data/unicode/DerivedGeneralCategory.txt | 206 ++- libcxx/utils/data/unicode/EastAsianWidth.txt | 115 +- .../data/unicode/GraphemeBreakProperty.txt | 96 +- .../utils/data/unicode/GraphemeBreakTest.txt | 464 +++--- libcxx/utils/data/unicode/emoji-data.txt | 42 +- 14 files changed, 2109 insertions(+), 1517 deletions(-) diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 82f1de6bad3942..24393607970238 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -46,6 +46,7 @@ Improvements and New Features - The ``std::ranges::{copy, copy_n, copy_backward}`` algorithms have been optimized for ``std::vector::iterator``\s, resulting in a performance improvement of up to 2000x. +- Updated formatting library to Unicode 16.0.0. Deprecations and Removals ------------------------- diff --git a/libcxx/include/__format/escaped_output_table.h b/libcxx/include/__format/escaped_output_table.h index 7a0b35239861e0..1401b4637d8396 100644 --- a/libcxx/include/__format/escaped_output_table.h +++ b/libcxx/include/__format/escaped_output_table.h @@ -109,7 +109,7 @@ namespace __escaped_output_table { /// - bits [14, 31] The lower bound code point of the range. The upper bound of /// the range is lower bound + size. Note the code expects code units the fit /// into 18 bits, instead of the 21 bits needed for the full Unicode range. -_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[735] = { 0x00000020 /* 00000000 - 00000020 [ 33] */, 0x001fc021 /* 0000007f - 000000a0 [ 34] */, 0x002b4000 /* 000000ad - 000000ad [ 1] */, @@ -136,7 +136,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x02170001 /* 0000085c - 0000085d [ 2] */, 0x0217c000 /* 0000085f - 0000085f [ 1] */, 0x021ac004 /* 0000086b - 0000086f [ 5] */, - 0x0223c008 /* 0000088f - 00000897 [ 9] */, + 0x0223c007 /* 0000088f - 00000896 [ 8] */, 0x02388000 /* 000008e2 - 000008e2 [ 1] */, 0x02610000 /* 00000984 - 00000984 [ 1] */, 0x02634001 /* 0000098d - 0000098e [ 2] */, @@ -331,12 +331,11 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x06a68005 /* 00001a9a - 00001a9f [ 6] */, 0x06ab8001 /* 00001aae - 00001aaf [ 2] */, 0x06b3c030 /* 00001acf - 00001aff [ 49] */, - 0x06d34002 /* 00001b4d - 00001b4f [ 3] */, - 0x06dfc000 /* 00001b7f - 00001b7f [ 1] */, + 0x06d34000 /* 00001b4d - 00001b4d [ 1] */, 0x06fd0007 /* 00001bf4 - 00001bfb [ 8] */, 0x070e0002 /* 00001c38 - 00001c3a [ 3] */, 0x07128002 /* 00001c4a - 00001c4c [ 3] */, - 0x07224006 /* 00001c89 - 00001c8f [ 7] */, + 0x0722c004 /* 00001c8b - 00001c8f [ 5] */, 0x072ec001 /* 00001cbb - 00001cbc [ 2] */, 0x07320007 /* 00001cc8 - 00001ccf [ 8] */, 0x073ec004 /* 00001cfb - 00001cff [ 5] */, @@ -364,7 +363,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x0830400e /* 000020c1 - 000020cf [ 15] */, 0x083c400e /* 000020f1 - 000020ff [ 15] */, 0x08630003 /* 0000218c - 0000218f [ 4] */, - 0x0909c018 /* 00002427 - 0000243f [ 25] */, + 0x090a8015 /* 0000242a - 0000243f [ 22] */, 0x0912c014 /* 0000244b - 0000245f [ 21] */, 0x0add0001 /* 00002b74 - 00002b75 [ 2] */, 0x0ae58000 /* 00002b96 - 00002b96 [ 1] */, @@ -393,16 +392,16 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x0c400004 /* 00003100 - 00003104 [ 5] */, 0x0c4c0000 /* 00003130 - 00003130 [ 1] */, 0x0c63c000 /* 0000318f - 0000318f [ 1] */, - 0x0c79000a /* 000031e4 - 000031ee [ 11] */, + 0x0c798008 /* 000031e6 - 000031ee [ 9] */, 0x0c87c000 /* 0000321f - 0000321f [ 1] */, 0x29234002 /* 0000a48d - 0000a48f [ 3] */, 0x2931c008 /* 0000a4c7 - 0000a4cf [ 9] */, 0x298b0013 /* 0000a62c - 0000a63f [ 20] */, 0x29be0007 /* 0000a6f8 - 0000a6ff [ 8] */, - 0x29f2c004 /* 0000a7cb - 0000a7cf [ 5] */, + 0x29f38001 /* 0000a7ce - 0000a7cf [ 2] */, 0x29f48000 /* 0000a7d2 - 0000a7d2 [ 1] */, 0x29f50000 /* 0000a7d4 - 0000a7d4 [ 1] */, - 0x29f68017 /* 0000a7da - 0000a7f1 [ 24] */, + 0x29f74014 /* 0000a7dd - 0000a7f1 [ 21] */, 0x2a0b4002 /* 0000a82d - 0000a82f [ 3] */, 0x2a0e8005 /* 0000a83a - 0000a83f [ 6] */, 0x2a1e0007 /* 0000a878 - 0000a87f [ 8] */, @@ -491,7 +490,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x41688000 /* 000105a2 - 000105a2 [ 1] */, 0x416c8000 /* 000105b2 - 000105b2 [ 1] */, 0x416e8000 /* 000105ba - 000105ba [ 1] */, - 0x416f4042 /* 000105bd - 000105ff [ 67] */, + 0x416f4002 /* 000105bd - 000105bf [ 3] */, + 0x417d000b /* 000105f4 - 000105ff [ 12] */, 0x41cdc008 /* 00010737 - 0001073f [ 9] */, 0x41d58009 /* 00010756 - 0001075f [ 10] */, 0x41da0017 /* 00010768 - 0001077f [ 24] */, @@ -534,11 +534,15 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x432cc00c /* 00010cb3 - 00010cbf [ 13] */, 0x433cc006 /* 00010cf3 - 00010cf9 [ 7] */, 0x434a0007 /* 00010d28 - 00010d2f [ 8] */, - 0x434e8125 /* 00010d3a - 00010e5f [ 294] */, + 0x434e8005 /* 00010d3a - 00010d3f [ 6] */, + 0x43598002 /* 00010d66 - 00010d68 [ 3] */, + 0x43618007 /* 00010d86 - 00010d8d [ 8] */, + 0x436400cf /* 00010d90 - 00010e5f [ 208] */, 0x439fc000 /* 00010e7f - 00010e7f [ 1] */, 0x43aa8000 /* 00010eaa - 00010eaa [ 1] */, 0x43ab8001 /* 00010eae - 00010eaf [ 2] */, - 0x43ac804a /* 00010eb2 - 00010efc [ 75] */, + 0x43ac800f /* 00010eb2 - 00010ec1 [ 16] */, + 0x43b14036 /* 00010ec5 - 00010efb [ 55] */, 0x43ca0007 /* 00010f28 - 00010f2f [ 8] */, 0x43d68015 /* 00010f5a - 00010f6f [ 22] */, 0x43e28025 /* 00010f8a - 00010faf [ 38] */, @@ -578,7 +582,18 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x44d60004 /* 00011358 - 0001135c [ 5] */, 0x44d90001 /* 00011364 - 00011365 [ 2] */, 0x44db4002 /* 0001136d - 0001136f [ 3] */, - 0x44dd408a /* 00011375 - 000113ff [ 139] */, + 0x44dd400a /* 00011375 - 0001137f [ 11] */, + 0x44e28000 /* 0001138a - 0001138a [ 1] */, + 0x44e30001 /* 0001138c - 0001138d [ 2] */, + 0x44e3c000 /* 0001138f - 0001138f [ 1] */, + 0x44ed8000 /* 000113b6 - 000113b6 [ 1] */, + 0x44f04000 /* 000113c1 - 000113c1 [ 1] */, + 0x44f0c001 /* 000113c3 - 000113c4 [ 2] */, + 0x44f18000 /* 000113c6 - 000113c6 [ 1] */, + 0x44f2c000 /* 000113cb - 000113cb [ 1] */, + 0x44f58000 /* 000113d6 - 000113d6 [ 1] */, + 0x44f64007 /* 000113d9 - 000113e0 [ 8] */, + 0x44f8c01c /* 000113e3 - 000113ff [ 29] */, 0x45170000 /* 0001145c - 0001145c [ 1] */, 0x4518801d /* 00011462 - 0001147f [ 30] */, 0x45320007 /* 000114c8 - 000114cf [ 8] */, @@ -589,7 +604,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x45968005 /* 0001165a - 0001165f [ 6] */, 0x459b4012 /* 0001166d - 0001167f [ 19] */, 0x45ae8005 /* 000116ba - 000116bf [ 6] */, - 0x45b28035 /* 000116ca - 000116ff [ 54] */, + 0x45b28005 /* 000116ca - 000116cf [ 6] */, + 0x45b9001b /* 000116e4 - 000116ff [ 28] */, 0x45c6c001 /* 0001171b - 0001171c [ 2] */, 0x45cb0003 /* 0001172c - 0001172f [ 4] */, 0x45d1c0b8 /* 00011747 - 000117ff [ 185] */, @@ -609,7 +625,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x46920007 /* 00011a48 - 00011a4f [ 8] */, 0x46a8c00c /* 00011aa3 - 00011aaf [ 13] */, 0x46be4006 /* 00011af9 - 00011aff [ 7] */, - 0x46c280f5 /* 00011b0a - 00011bff [ 246] */, + 0x46c280b5 /* 00011b0a - 00011bbf [ 182] */, + 0x46f8800d /* 00011be2 - 00011bef [ 14] */, + 0x46fe8005 /* 00011bfa - 00011bff [ 6] */, 0x47024000 /* 00011c09 - 00011c09 [ 1] */, 0x470dc000 /* 00011c37 - 00011c37 [ 1] */, 0x47118009 /* 00011c46 - 00011c4f [ 10] */, @@ -633,7 +651,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x47be4006 /* 00011ef9 - 00011eff [ 7] */, 0x47c44000 /* 00011f11 - 00011f11 [ 1] */, 0x47cec002 /* 00011f3b - 00011f3d [ 3] */, - 0x47d68055 /* 00011f5a - 00011faf [ 86] */, + 0x47d6c054 /* 00011f5b - 00011faf [ 85] */, 0x47ec400e /* 00011fb1 - 00011fbf [ 15] */, 0x47fc800c /* 00011ff2 - 00011ffe [ 13] */, 0x48e68065 /* 0001239a - 000123ff [ 102] */, @@ -642,8 +660,10 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x49510a4b /* 00012544 - 00012f8f [ 2636] */, 0x4bfcc00c /* 00012ff3 - 00012fff [ 13] */, 0x4d0c000f /* 00013430 - 0001343f [ 16] */, - 0x4d158fa9 /* 00013456 - 000143ff [ 4010] */, - 0x5191e1b8 /* 00014647 - 000167ff [ 8633] */, + 0x4d158009 /* 00013456 - 0001345f [ 10] */, + 0x50fec004 /* 000143fb - 000143ff [ 5] */, + 0x5191dab8 /* 00014647 - 000160ff [ 6841] */, + 0x584e86c5 /* 0001613a - 000167ff [ 1734] */, 0x5a8e4006 /* 00016a39 - 00016a3f [ 7] */, 0x5a97c000 /* 00016a5f - 00016a5f [ 1] */, 0x5a9a8003 /* 00016a6a - 00016a6d [ 4] */, @@ -655,7 +675,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x5ad68000 /* 00016b5a - 00016b5a [ 1] */, 0x5ad88000 /* 00016b62 - 00016b62 [ 1] */, 0x5ade0004 /* 00016b78 - 00016b7c [ 5] */, - 0x5ae402af /* 00016b90 - 00016e3f [ 688] */, + 0x5ae401af /* 00016b90 - 00016d3f [ 432] */, + 0x5b5e80c5 /* 00016d7a - 00016e3f [ 198] */, 0x5ba6c064 /* 00016e9b - 00016eff [ 101] */, 0x5bd2c003 /* 00016f4b - 00016f4e [ 4] */, 0x5be20006 /* 00016f88 - 00016f8e [ 7] */, @@ -663,7 +684,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x5bf9400a /* 00016fe5 - 00016fef [ 11] */, 0x5bfc800d /* 00016ff2 - 00016fff [ 14] */, 0x61fe0007 /* 000187f8 - 000187ff [ 8] */, - 0x63358029 /* 00018cd6 - 00018cff [ 42] */, + 0x63358028 /* 00018cd6 - 00018cfe [ 41] */, 0x634262e6 /* 00018d09 - 0001afef [ 8935] */, 0x6bfd0000 /* 0001aff4 - 0001aff4 [ 1] */, 0x6bff0000 /* 0001affc - 0001affc [ 1] */, @@ -678,7 +699,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x6f1f4002 /* 0001bc7d - 0001bc7f [ 3] */, 0x6f224006 /* 0001bc89 - 0001bc8f [ 7] */, 0x6f268001 /* 0001bc9a - 0001bc9b [ 2] */, - 0x6f28125f /* 0001bca0 - 0001ceff [ 4704] */, + 0x6f280f5f /* 0001bca0 - 0001cbff [ 3936] */, + 0x733e8005 /* 0001ccfa - 0001ccff [ 6] */, + 0x73ad004b /* 0001ceb4 - 0001ceff [ 76] */, 0x73cb8001 /* 0001cf2e - 0001cf2f [ 2] */, 0x73d1c008 /* 0001cf47 - 0001cf4f [ 9] */, 0x73f1003b /* 0001cfc4 - 0001cfff [ 60] */, @@ -730,7 +753,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x78abc010 /* 0001e2af - 0001e2bf [ 17] */, 0x78be8004 /* 0001e2fa - 0001e2fe [ 5] */, 0x78c001cf /* 0001e300 - 0001e4cf [ 464] */, - 0x793e82e5 /* 0001e4fa - 0001e7df [ 742] */, + 0x793e80d5 /* 0001e4fa - 0001e5cf [ 214] */, + 0x797ec003 /* 0001e5fb - 0001e5fe [ 4] */, + 0x798001df /* 0001e600 - 0001e7df [ 480] */, 0x79f9c000 /* 0001e7e7 - 0001e7e7 [ 1] */, 0x79fb0000 /* 0001e7ec - 0001e7ec [ 1] */, 0x79fbc000 /* 0001e7ef - 0001e7ef [ 1] */, @@ -800,18 +825,17 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { 0x7e168005 /* 0001f85a - 0001f85f [ 6] */, 0x7e220007 /* 0001f888 - 0001f88f [ 8] */, 0x7e2b8001 /* 0001f8ae - 0001f8af [ 2] */, - 0x7e2c804d /* 0001f8b2 - 0001f8ff [ 78] */, + 0x7e2f0003 /* 0001f8bc - 0001f8bf [ 4] */, + 0x7e30803d /* 0001f8c2 - 0001f8ff [ 62] */, 0x7e95000b /* 0001fa54 - 0001fa5f [ 12] */, 0x7e9b8001 /* 0001fa6e - 0001fa6f [ 2] */, 0x7e9f4002 /* 0001fa7d - 0001fa7f [ 3] */, - 0x7ea24006 /* 0001fa89 - 0001fa8f [ 7] */, - 0x7eaf8000 /* 0001fabe - 0001fabe [ 1] */, - 0x7eb18007 /* 0001fac6 - 0001facd [ 8] */, - 0x7eb70003 /* 0001fadc - 0001fadf [ 4] */, - 0x7eba4006 /* 0001fae9 - 0001faef [ 7] */, + 0x7ea28004 /* 0001fa8a - 0001fa8e [ 5] */, + 0x7eb1c006 /* 0001fac7 - 0001facd [ 7] */, + 0x7eb74001 /* 0001fadd - 0001fade [ 2] */, + 0x7eba8005 /* 0001faea - 0001faef [ 6] */, 0x7ebe4006 /* 0001faf9 - 0001faff [ 7] */, 0x7ee4c000 /* 0001fb93 - 0001fb93 [ 1] */, - 0x7ef2c024 /* 0001fbcb - 0001fbef [ 37] */, 0x7efe8405 /* 0001fbfa - 0001ffff [ 1030] */, 0xa9b8001f /* 0002a6e0 - 0002a6ff [ 32] */, 0xadce8005 /* 0002b73a - 0002b73f [ 6] */, diff --git a/libcxx/include/__format/extended_grapheme_cluster_table.h b/libcxx/include/__format/extended_grapheme_cluster_table.h index 7653a9e03b815d..f76e018df7ae11 100644 --- a/libcxx/include/__format/extended_grapheme_cluster_table.h +++ b/libcxx/include/__format/extended_grapheme_cluster_table.h @@ -125,7 +125,7 @@ enum class __property : uint8_t { /// following benchmark. /// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp // clang-format off -_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1501] = { 0x00000091, 0x00005005, 0x00005811, @@ -164,7 +164,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x00414842, 0x0042c822, 0x00448018, - 0x0044c072, + 0x0044b882, 0x00465172, 0x00471008, 0x004719f2, @@ -246,14 +246,12 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0064101a, 0x0065e002, 0x0065f00a, - 0x0065f802, - 0x0066001a, + 0x0065f812, + 0x0066080a, 0x00661002, 0x0066181a, - 0x00663002, - 0x0066381a, - 0x0066501a, - 0x00666012, + 0x00663022, + 0x00665032, 0x0066a812, 0x00671012, 0x0067980a, @@ -318,10 +316,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x008b047c, 0x008d457b, 0x009ae822, - 0x00b89022, - 0x00b8a80a, - 0x00b99012, - 0x00b9a00a, + 0x00b89032, + 0x00b99022, 0x00ba9012, 0x00bb9012, 0x00bda012, @@ -361,29 +357,23 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x00d581e2, 0x00d80032, 0x00d8200a, - 0x00d9a062, - 0x00d9d80a, - 0x00d9e002, - 0x00d9e84a, - 0x00da1002, - 0x00da181a, + 0x00d9a092, + 0x00d9f03a, + 0x00da1022, 0x00db5882, 0x00dc0012, 0x00dc100a, 0x00dd080a, 0x00dd1032, 0x00dd301a, - 0x00dd4012, - 0x00dd500a, - 0x00dd5822, + 0x00dd4052, 0x00df3002, 0x00df380a, 0x00df4012, 0x00df502a, 0x00df6802, 0x00df700a, - 0x00df7822, - 0x00df901a, + 0x00df7842, 0x00e1207a, 0x00e16072, 0x00e1a01a, @@ -475,7 +465,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0547f802, 0x05493072, 0x054a38a2, - 0x054a901a, + 0x054a900a, + 0x054a9802, 0x054b01c4, 0x054c0022, 0x054c180a, @@ -484,7 +475,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x054db032, 0x054dd01a, 0x054de012, - 0x054df02a, + 0x054df01a, + 0x054e0002, 0x054f2802, 0x05514852, 0x0551781a, @@ -1328,8 +1320,9 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0851f802, 0x08572812, 0x08692032, + 0x086b4842, 0x08755812, - 0x0877e822, + 0x0877e032, 0x087a30a2, 0x087c1032, 0x0880000a, @@ -1357,7 +1350,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x088c100a, 0x088d982a, 0x088db082, - 0x088df81a, + 0x088df80a, + 0x088e0002, 0x088e1018, 0x088e4832, 0x088e700a, @@ -1365,9 +1359,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0891602a, 0x08917822, 0x0891901a, - 0x0891a002, - 0x0891a80a, - 0x0891b012, + 0x0891a032, 0x0891f002, 0x08920802, 0x0896f802, @@ -1381,11 +1373,24 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x089a0002, 0x089a083a, 0x089a381a, - 0x089a582a, + 0x089a581a, + 0x089a6802, 0x089ab802, 0x089b101a, 0x089b3062, 0x089b8042, + 0x089dc002, + 0x089dc81a, + 0x089dd852, + 0x089e1002, + 0x089e2802, + 0x089e3822, + 0x089e500a, + 0x089e601a, + 0x089e7022, + 0x089e8808, + 0x089e9002, + 0x089f0812, 0x08a1a82a, 0x08a1c072, 0x08a2001a, @@ -1422,10 +1427,10 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x08b5600a, 0x08b56802, 0x08b5701a, - 0x08b58052, - 0x08b5b00a, - 0x08b5b802, - 0x08b8e822, + 0x08b58072, + 0x08b8e802, + 0x08b8f00a, + 0x08b8f802, 0x08b91032, 0x08b9300a, 0x08b93842, @@ -1436,9 +1441,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x08c98002, 0x08c9884a, 0x08c9b81a, - 0x08c9d812, - 0x08c9e80a, - 0x08c9f002, + 0x08c9d832, 0x08c9f808, 0x08ca000a, 0x08ca0808, @@ -1495,28 +1498,29 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x08f9a01a, 0x08f9b042, 0x08f9f01a, - 0x08fa0002, - 0x08fa080a, - 0x08fa1002, + 0x08fa0022, + 0x08fad002, 0x09a180f1, 0x09a20002, 0x09a238e2, + 0x0b08f0b2, + 0x0b09502a, + 0x0b096822, 0x0b578042, 0x0b598062, + 0x0b6b180c, + 0x0b6b383c, 0x0b7a7802, 0x0b7a8b6a, 0x0b7c7832, 0x0b7f2002, - 0x0b7f801a, + 0x0b7f8012, 0x0de4e812, 0x0de50031, 0x0e7802d2, 0x0e798162, - 0x0e8b2802, - 0x0e8b300a, - 0x0e8b3822, - 0x0e8b680a, - 0x0e8b7042, + 0x0e8b2842, + 0x0e8b6852, 0x0e8b9871, 0x0e8bd872, 0x0e8c2862, @@ -1538,6 +1542,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { 0x0f157002, 0x0f176032, 0x0f276032, + 0x0f2f7012, 0x0f468062, 0x0f4a2062, 0x0f8007f3, diff --git a/libcxx/include/__format/indic_conjunct_break_table.h b/libcxx/include/__format/indic_conjunct_break_table.h index df6cfe6a02f348..f48ea625908e99 100644 --- a/libcxx/include/__format/indic_conjunct_break_table.h +++ b/libcxx/include/__format/indic_conjunct_break_table.h @@ -107,10 +107,9 @@ enum class __property : uint8_t { /// following benchmark. /// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp // clang-format off -_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { - 0x00180139, - 0x001a807d, - 0x00241811, +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[403] = { + 0x001801bd, + 0x00241819, 0x002c88b1, 0x002df801, 0x002e0805, @@ -125,6 +124,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { 0x0037500d, 0x00388801, 0x00398069, + 0x003d3029, 0x003f5821, 0x003fe801, 0x0040b00d, @@ -132,87 +132,174 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { 0x00412809, 0x00414811, 0x0042c809, - 0x0044c01d, + 0x0044b821, 0x0046505d, - 0x00471871, + 0x0047187d, 0x0048a890, + 0x0049d001, 0x0049e001, + 0x004a081d, 0x004a6802, - 0x004a880d, + 0x004a8819, 0x004ac01c, + 0x004b1005, 0x004bc01c, + 0x004c0801, 0x004ca84c, 0x004d5018, 0x004d9000, 0x004db00c, 0x004de001, + 0x004df001, + 0x004e080d, 0x004e6802, + 0x004eb801, 0x004ee004, 0x004ef800, + 0x004f1005, 0x004f8004, 0x004ff001, + 0x00500805, 0x0051e001, + 0x00520805, + 0x00523805, + 0x00525809, + 0x00528801, + 0x00538005, + 0x0053a801, + 0x00540805, 0x0054a84c, 0x00555018, 0x00559004, 0x0055a810, 0x0055e001, + 0x00560811, + 0x00563805, 0x00566802, + 0x00571005, 0x0057c800, + 0x0057d015, + 0x00580801, 0x0058a84c, 0x00595018, 0x00599004, 0x0059a810, 0x0059e001, + 0x0059f005, + 0x005a080d, 0x005a6802, + 0x005aa809, 0x005ae004, 0x005af800, + 0x005b1005, 0x005b8800, + 0x005c1001, + 0x005df001, + 0x005e0001, + 0x005e6801, + 0x005eb801, + 0x00600001, + 0x00602001, 0x0060a84c, 0x0061503c, 0x0061e001, + 0x0061f009, + 0x00623009, + 0x00625009, 0x00626802, 0x0062a805, 0x0062c008, + 0x00631005, + 0x00640801, 0x0065e001, + 0x0065f805, + 0x00661001, + 0x00663009, + 0x0066500d, + 0x0066a805, + 0x00671005, + 0x00680005, 0x0068a894, 0x0069d805, + 0x0069f001, + 0x006a080d, 0x006a6802, - 0x0071c009, - 0x0072400d, - 0x0075c009, - 0x0076400d, + 0x006ab801, + 0x006b1005, + 0x006c0801, + 0x006e5001, + 0x006e7801, + 0x006e9009, + 0x006eb001, + 0x006ef801, + 0x00718801, + 0x0071a019, + 0x0072381d, + 0x00758801, + 0x0075a021, + 0x00764019, 0x0078c005, 0x0079a801, 0x0079b801, 0x0079c801, - 0x007b8805, - 0x007ba001, - 0x007bd00d, - 0x007c0001, - 0x007c1009, + 0x007b8835, + 0x007c0011, 0x007c3005, + 0x007c6829, + 0x007cc88d, 0x007e3001, - 0x0081b801, + 0x0081680d, + 0x00819015, 0x0081c805, + 0x0081e805, + 0x0082c005, + 0x0082f009, + 0x0083880d, + 0x00841001, + 0x00842805, 0x00846801, + 0x0084e801, 0x009ae809, - 0x00b8a001, - 0x00be9001, + 0x00b8900d, + 0x00b99009, + 0x00ba9005, + 0x00bb9005, + 0x00bda005, + 0x00bdb819, + 0x00be3001, + 0x00be4829, 0x00bee801, + 0x00c05809, + 0x00c07801, + 0x00c42805, 0x00c54801, + 0x00c90009, + 0x00c93805, + 0x00c99001, 0x00c9c809, 0x00d0b805, + 0x00d0d801, + 0x00d2b001, + 0x00d2c019, 0x00d30001, - 0x00d3a81d, + 0x00d31001, + 0x00d3281d, + 0x00d39825, 0x00d3f801, - 0x00d58035, - 0x00d5f83d, - 0x00d9a001, + 0x00d58079, + 0x00d8000d, + 0x00d9a025, + 0x00da1009, 0x00db5821, - 0x00dd5801, + 0x00dc0005, + 0x00dd100d, + 0x00dd4015, 0x00df3001, - 0x00e1b801, + 0x00df4005, + 0x00df6801, + 0x00df7811, + 0x00e1601d, + 0x00e1b005, 0x00e68009, 0x00e6a031, 0x00e71019, @@ -221,82 +308,193 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { 0x00e7c005, 0x00ee00fd, 0x01006801, - 0x01068031, - 0x01070801, - 0x0107282d, + 0x01068081, 0x01677809, 0x016bf801, 0x016f007d, 0x01815015, 0x0184c805, - 0x05337801, + 0x0533780d, 0x0533a025, 0x0534f005, 0x05378005, + 0x05401001, + 0x05403001, + 0x05405801, + 0x05412805, 0x05416001, + 0x05462005, 0x05470045, - 0x05495809, + 0x0547f801, + 0x0549301d, + 0x054a3829, + 0x054a9801, + 0x054c0009, 0x054d9801, + 0x054db00d, + 0x054de005, + 0x054e0001, + 0x054f2801, + 0x05514815, + 0x05518805, + 0x0551a805, + 0x05521801, + 0x05526001, + 0x0553e001, 0x05558001, 0x05559009, 0x0555b805, 0x0555f005, 0x05560801, + 0x05576005, 0x0557b001, + 0x055f2801, + 0x055f4001, 0x055f6801, 0x07d8f001, + 0x07f0003d, 0x07f1003d, + 0x07fcf005, 0x080fe801, 0x08170001, 0x081bb011, - 0x08506801, - 0x08507801, + 0x08500809, + 0x08502805, + 0x0850600d, 0x0851c009, 0x0851f801, 0x08572805, 0x0869200d, + 0x086b4811, 0x08755805, - 0x0877e809, + 0x0877e00d, 0x087a3029, 0x087c100d, + 0x08800801, + 0x0881c039, 0x08838001, - 0x0883f801, - 0x0885d001, + 0x08839805, + 0x0883f809, + 0x0885980d, + 0x0885c805, + 0x08861001, 0x08880009, - 0x08899805, + 0x08893811, + 0x0889681d, 0x088b9801, - 0x088e5001, - 0x0891b001, - 0x08974805, + 0x088c0005, + 0x088db021, + 0x088e0001, + 0x088e480d, + 0x088e7801, + 0x08917809, + 0x0891a00d, + 0x0891f001, + 0x08920801, + 0x0896f801, + 0x0897181d, + 0x08980005, 0x0899d805, + 0x0899f001, + 0x089a0001, + 0x089a6801, + 0x089ab801, 0x089b3019, 0x089b8011, + 0x089dc001, + 0x089dd815, + 0x089e1001, + 0x089e2801, + 0x089e3809, + 0x089e7009, + 0x089e9001, + 0x089f0805, + 0x08a1c01d, + 0x08a21009, 0x08a23001, 0x08a2f001, - 0x08a61801, - 0x08ae0001, - 0x08b5b801, - 0x08b95801, - 0x08c1d001, - 0x08c9f001, + 0x08a58001, + 0x08a59815, + 0x08a5d001, + 0x08a5e801, + 0x08a5f805, + 0x08a61005, + 0x08ad7801, + 0x08ad900d, + 0x08ade005, + 0x08adf805, + 0x08aee005, + 0x08b1981d, + 0x08b1e801, + 0x08b1f805, + 0x08b55801, + 0x08b56801, + 0x08b5801d, + 0x08b8e801, + 0x08b8f801, + 0x08b9100d, + 0x08b93811, + 0x08c17821, + 0x08c1c805, + 0x08c98001, + 0x08c9d80d, 0x08ca1801, - 0x08d1a001, + 0x08cea00d, + 0x08ced005, + 0x08cf0001, + 0x08d00825, + 0x08d19815, + 0x08d1d80d, 0x08d23801, - 0x08d4c801, - 0x08ea1001, - 0x08ea2005, + 0x08d28815, + 0x08d2c809, + 0x08d45031, + 0x08d4c005, + 0x08e18019, + 0x08e1c015, + 0x08e1f801, + 0x08e49055, + 0x08e55019, + 0x08e59005, + 0x08e5a805, + 0x08e98815, + 0x08e9d001, + 0x08e9e005, + 0x08e9f819, + 0x08ea3801, + 0x08ec8005, + 0x08eca801, 0x08ecb801, - 0x08fa1001, + 0x08f79805, + 0x08f80005, + 0x08f9b011, + 0x08fa0009, + 0x08fad001, + 0x09a20001, + 0x09a23839, + 0x0b08f02d, + 0x0b096809, 0x0b578011, 0x0b598019, - 0x0de4f001, - 0x0e8b2801, - 0x0e8b3809, - 0x0e8b7011, + 0x0b7a7801, + 0x0b7c780d, + 0x0b7f2001, + 0x0b7f8005, + 0x0de4e805, + 0x0e7800b5, + 0x0e798059, + 0x0e8b2811, + 0x0e8b6815, 0x0e8bd81d, 0x0e8c2819, 0x0e8d500d, 0x0e921009, + 0x0ed000d9, + 0x0ed1d8c5, + 0x0ed3a801, + 0x0ed42001, + 0x0ed4d811, + 0x0ed50839, 0x0f000019, 0x0f004041, 0x0f00d819, @@ -307,8 +505,12 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { 0x0f157001, 0x0f17600d, 0x0f27600d, + 0x0f2f7005, 0x0f468019, - 0x0f4a2019}; + 0x0f4a2019, + 0x0f9fd811, + 0x7001017d, + 0x700803bd}; // clang-format on /// Returns the indic conjuct break property of a code point. diff --git a/libcxx/include/__format/width_estimation_table.h b/libcxx/include/__format/width_estimation_table.h index 5b4b3950c6a1d0..0ea0b4f413a748 100644 --- a/libcxx/include/__format/width_estimation_table.h +++ b/libcxx/include/__format/width_estimation_table.h @@ -119,7 +119,7 @@ namespace __width_estimation_table { /// - bits [0, 13] The size of the range, allowing 16384 elements. /// - bits [14, 31] The lower bound code point of the range. The upper bound of /// the range is lower bound + size. -_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[110] = { 0x0440005f /* 00001100 - 0000115f [ 96] */, // 0x08c68001 /* 0000231a - 0000231b [ 2] */, // 0x08ca4001 /* 00002329 - 0000232a [ 2] */, // @@ -128,8 +128,10 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { 0x08fcc000 /* 000023f3 - 000023f3 [ 1] */, // 0x097f4001 /* 000025fd - 000025fe [ 2] */, // 0x09850001 /* 00002614 - 00002615 [ 2] */, // + 0x098c0007 /* 00002630 - 00002637 [ 8] */, // 0x0992000b /* 00002648 - 00002653 [ 12] */, // 0x099fc000 /* 0000267f - 0000267f [ 1] */, // + 0x09a28005 /* 0000268a - 0000268f [ 6] */, // 0x09a4c000 /* 00002693 - 00002693 [ 1] */, // 0x09a84000 /* 000026a1 - 000026a1 [ 1] */, // 0x09aa8001 /* 000026aa - 000026ab [ 2] */, // @@ -163,7 +165,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { 0x0c264066 /* 00003099 - 000030ff [ 103] */, // 0x0c41402a /* 00003105 - 0000312f [ 43] */, // 0x0c4c405d /* 00003131 - 0000318e [ 94] */, // - 0x0c640053 /* 00003190 - 000031e3 [ 84] */, // + 0x0c640055 /* 00003190 - 000031e5 [ 86] */, // 0x0c7bc02f /* 000031ef - 0000321e [ 48] */, // 0x0c880027 /* 00003220 - 00003247 [ 40] */, // 0x0c943fff /* 00003250 - 0000724f [16384] */, // @@ -182,7 +184,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { 0x5bfc0001 /* 00016ff0 - 00016ff1 [ 2] */, // 0x5c0017f7 /* 00017000 - 000187f7 [ 6136] */, // 0x620004d5 /* 00018800 - 00018cd5 [ 1238] */, // - 0x63400008 /* 00018d00 - 00018d08 [ 9] */, // + 0x633fc009 /* 00018cff - 00018d08 [ 10] */, // 0x6bfc0003 /* 0001aff0 - 0001aff3 [ 4] */, // 0x6bfd4006 /* 0001aff5 - 0001affb [ 7] */, // 0x6bff4001 /* 0001affd - 0001affe [ 2] */, // @@ -192,6 +194,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { 0x6c554000 /* 0001b155 - 0001b155 [ 1] */, // 0x6c590003 /* 0001b164 - 0001b167 [ 4] */, // 0x6c5c018b /* 0001b170 - 0001b2fb [ 396] */, // + 0x74c00056 /* 0001d300 - 0001d356 [ 87] */, // + 0x74d80016 /* 0001d360 - 0001d376 [ 23] */, // 0x7c010000 /* 0001f004 - 0001f004 [ 1] */, // 0x7c33c000 /* 0001f0cf - 0001f0cf [ 1] */, // 0x7c638000 /* 0001f18e - 0001f18e [ 1] */, // @@ -213,11 +217,10 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { 0x7dfc0000 /* 0001f7f0 - 0001f7f0 [ 1] */, // 0x7e4000ff /* 0001f900 - 0001f9ff [ 256] */, // 0x7e9c000c /* 0001fa70 - 0001fa7c [ 13] */, // - 0x7ea00008 /* 0001fa80 - 0001fa88 [ 9] */, // - 0x7ea4002d /* 0001fa90 - 0001fabd [ 46] */, // - 0x7eafc006 /* 0001fabf - 0001fac5 [ 7] */, // - 0x7eb3800d /* 0001face - 0001fadb [ 14] */, // - 0x7eb80008 /* 0001fae0 - 0001fae8 [ 9] */, // + 0x7ea00009 /* 0001fa80 - 0001fa89 [ 10] */, // + 0x7ea3c037 /* 0001fa8f - 0001fac6 [ 56] */, // + 0x7eb3800e /* 0001face - 0001fadc [ 15] */, // + 0x7eb7c00a /* 0001fadf - 0001fae9 [ 11] */, // 0x7ebc0008 /* 0001faf0 - 0001faf8 [ 9] */, // 0x80003fff /* 00020000 - 00023fff [16384] */, // 0x90003fff /* 00024000 - 00027fff [16384] */, // diff --git a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/escaped_output.pass.cpp b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/escaped_output.pass.cpp index 430495e1aba8ee..d24db360173b12 100644 --- a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/escaped_output.pass.cpp +++ b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/escaped_output.pass.cpp @@ -48,7 +48,7 @@ inline constexpr int Cc = 65; inline constexpr int Cf = 170; inline constexpr int Cs = 2'048; inline constexpr int Co = 137'468; -inline constexpr int Cn = 824'718; +inline constexpr int Cn = 819'533; inline constexpr int C = Cc + Cf + Cs + Co + Cn; // This is the final part of the Unicode properties table: diff --git a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h index eb7500a828ccf0..9664622ab4e403 100644 --- a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h +++ b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.h @@ -82,7 +82,7 @@ struct data { }; /// The data for UTF-8. -std::array, 1187> data_utf8 = {{ +std::array, 1093> data_utf8 = {{ {"\U00000020\U00000020", {32, 32}, {1, 2}}, {"\U00000020\U00000308\U00000020", {32, 32}, {3, 4}}, {"\U00000020\U0000000d", {32, 13}, {1, 2}}, @@ -91,8 +91,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000020\U00000308\U0000000a", {32, 10}, {3, 4}}, {"\U00000020\U00000001", {32, 1}, {1, 2}}, {"\U00000020\U00000308\U00000001", {32, 1}, {3, 4}}, - {"\U00000020\U0000034f", {32}, {3}}, - {"\U00000020\U00000308\U0000034f", {32}, {5}}, + {"\U00000020\U0000200c", {32}, {4}}, + {"\U00000020\U00000308\U0000200c", {32}, {6}}, {"\U00000020\U0001f1e6", {32, 127462}, {1, 5}}, {"\U00000020\U00000308\U0001f1e6", {32, 127462}, {3, 7}}, {"\U00000020\U00000600", {32, 1536}, {1, 3}}, @@ -109,8 +109,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000020\U00000308\U0000ac00", {32, 44032}, {3, 6}}, {"\U00000020\U0000ac01", {32, 44033}, {1, 4}}, {"\U00000020\U00000308\U0000ac01", {32, 44033}, {3, 6}}, - {"\U00000020\U00000900", {32}, {4}}, - {"\U00000020\U00000308\U00000900", {32}, {6}}, {"\U00000020\U00000903", {32}, {4}}, {"\U00000020\U00000308\U00000903", {32}, {6}}, {"\U00000020\U00000904", {32, 2308}, {1, 4}}, @@ -123,8 +121,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000020\U00000308\U0000231a", {32, 8986}, {3, 6}}, {"\U00000020\U00000300", {32}, {3}}, {"\U00000020\U00000308\U00000300", {32}, {5}}, - {"\U00000020\U0000093c", {32}, {4}}, - {"\U00000020\U00000308\U0000093c", {32}, {6}}, + {"\U00000020\U00000900", {32}, {4}}, + {"\U00000020\U00000308\U00000900", {32}, {6}}, {"\U00000020\U0000094d", {32}, {4}}, {"\U00000020\U00000308\U0000094d", {32}, {6}}, {"\U00000020\U0000200d", {32}, {4}}, @@ -139,8 +137,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000000d\U00000308\U0000000a", {13, 776, 10}, {1, 3, 4}}, {"\U0000000d\U00000001", {13, 1}, {1, 2}}, {"\U0000000d\U00000308\U00000001", {13, 776, 1}, {1, 3, 4}}, - {"\U0000000d\U0000034f", {13, 847}, {1, 3}}, - {"\U0000000d\U00000308\U0000034f", {13, 776}, {1, 5}}, + {"\U0000000d\U0000200c", {13, 8204}, {1, 4}}, + {"\U0000000d\U00000308\U0000200c", {13, 776}, {1, 6}}, {"\U0000000d\U0001f1e6", {13, 127462}, {1, 5}}, {"\U0000000d\U00000308\U0001f1e6", {13, 776, 127462}, {1, 3, 7}}, {"\U0000000d\U00000600", {13, 1536}, {1, 3}}, @@ -157,8 +155,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000000d\U00000308\U0000ac00", {13, 776, 44032}, {1, 3, 6}}, {"\U0000000d\U0000ac01", {13, 44033}, {1, 4}}, {"\U0000000d\U00000308\U0000ac01", {13, 776, 44033}, {1, 3, 6}}, - {"\U0000000d\U00000900", {13, 2304}, {1, 4}}, - {"\U0000000d\U00000308\U00000900", {13, 776}, {1, 6}}, {"\U0000000d\U00000903", {13, 2307}, {1, 4}}, {"\U0000000d\U00000308\U00000903", {13, 776}, {1, 6}}, {"\U0000000d\U00000904", {13, 2308}, {1, 4}}, @@ -171,8 +167,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000000d\U00000308\U0000231a", {13, 776, 8986}, {1, 3, 6}}, {"\U0000000d\U00000300", {13, 768}, {1, 3}}, {"\U0000000d\U00000308\U00000300", {13, 776}, {1, 5}}, - {"\U0000000d\U0000093c", {13, 2364}, {1, 4}}, - {"\U0000000d\U00000308\U0000093c", {13, 776}, {1, 6}}, + {"\U0000000d\U00000900", {13, 2304}, {1, 4}}, + {"\U0000000d\U00000308\U00000900", {13, 776}, {1, 6}}, {"\U0000000d\U0000094d", {13, 2381}, {1, 4}}, {"\U0000000d\U00000308\U0000094d", {13, 776}, {1, 6}}, {"\U0000000d\U0000200d", {13, 8205}, {1, 4}}, @@ -187,8 +183,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000000a\U00000308\U0000000a", {10, 776, 10}, {1, 3, 4}}, {"\U0000000a\U00000001", {10, 1}, {1, 2}}, {"\U0000000a\U00000308\U00000001", {10, 776, 1}, {1, 3, 4}}, - {"\U0000000a\U0000034f", {10, 847}, {1, 3}}, - {"\U0000000a\U00000308\U0000034f", {10, 776}, {1, 5}}, + {"\U0000000a\U0000200c", {10, 8204}, {1, 4}}, + {"\U0000000a\U00000308\U0000200c", {10, 776}, {1, 6}}, {"\U0000000a\U0001f1e6", {10, 127462}, {1, 5}}, {"\U0000000a\U00000308\U0001f1e6", {10, 776, 127462}, {1, 3, 7}}, {"\U0000000a\U00000600", {10, 1536}, {1, 3}}, @@ -205,8 +201,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000000a\U00000308\U0000ac00", {10, 776, 44032}, {1, 3, 6}}, {"\U0000000a\U0000ac01", {10, 44033}, {1, 4}}, {"\U0000000a\U00000308\U0000ac01", {10, 776, 44033}, {1, 3, 6}}, - {"\U0000000a\U00000900", {10, 2304}, {1, 4}}, - {"\U0000000a\U00000308\U00000900", {10, 776}, {1, 6}}, {"\U0000000a\U00000903", {10, 2307}, {1, 4}}, {"\U0000000a\U00000308\U00000903", {10, 776}, {1, 6}}, {"\U0000000a\U00000904", {10, 2308}, {1, 4}}, @@ -219,8 +213,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000000a\U00000308\U0000231a", {10, 776, 8986}, {1, 3, 6}}, {"\U0000000a\U00000300", {10, 768}, {1, 3}}, {"\U0000000a\U00000308\U00000300", {10, 776}, {1, 5}}, - {"\U0000000a\U0000093c", {10, 2364}, {1, 4}}, - {"\U0000000a\U00000308\U0000093c", {10, 776}, {1, 6}}, + {"\U0000000a\U00000900", {10, 2304}, {1, 4}}, + {"\U0000000a\U00000308\U00000900", {10, 776}, {1, 6}}, {"\U0000000a\U0000094d", {10, 2381}, {1, 4}}, {"\U0000000a\U00000308\U0000094d", {10, 776}, {1, 6}}, {"\U0000000a\U0000200d", {10, 8205}, {1, 4}}, @@ -235,8 +229,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000001\U00000308\U0000000a", {1, 776, 10}, {1, 3, 4}}, {"\U00000001\U00000001", {1, 1}, {1, 2}}, {"\U00000001\U00000308\U00000001", {1, 776, 1}, {1, 3, 4}}, - {"\U00000001\U0000034f", {1, 847}, {1, 3}}, - {"\U00000001\U00000308\U0000034f", {1, 776}, {1, 5}}, + {"\U00000001\U0000200c", {1, 8204}, {1, 4}}, + {"\U00000001\U00000308\U0000200c", {1, 776}, {1, 6}}, {"\U00000001\U0001f1e6", {1, 127462}, {1, 5}}, {"\U00000001\U00000308\U0001f1e6", {1, 776, 127462}, {1, 3, 7}}, {"\U00000001\U00000600", {1, 1536}, {1, 3}}, @@ -253,8 +247,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000001\U00000308\U0000ac00", {1, 776, 44032}, {1, 3, 6}}, {"\U00000001\U0000ac01", {1, 44033}, {1, 4}}, {"\U00000001\U00000308\U0000ac01", {1, 776, 44033}, {1, 3, 6}}, - {"\U00000001\U00000900", {1, 2304}, {1, 4}}, - {"\U00000001\U00000308\U00000900", {1, 776}, {1, 6}}, {"\U00000001\U00000903", {1, 2307}, {1, 4}}, {"\U00000001\U00000308\U00000903", {1, 776}, {1, 6}}, {"\U00000001\U00000904", {1, 2308}, {1, 4}}, @@ -267,62 +259,60 @@ std::array, 1187> data_utf8 = {{ {"\U00000001\U00000308\U0000231a", {1, 776, 8986}, {1, 3, 6}}, {"\U00000001\U00000300", {1, 768}, {1, 3}}, {"\U00000001\U00000308\U00000300", {1, 776}, {1, 5}}, - {"\U00000001\U0000093c", {1, 2364}, {1, 4}}, - {"\U00000001\U00000308\U0000093c", {1, 776}, {1, 6}}, + {"\U00000001\U00000900", {1, 2304}, {1, 4}}, + {"\U00000001\U00000308\U00000900", {1, 776}, {1, 6}}, {"\U00000001\U0000094d", {1, 2381}, {1, 4}}, {"\U00000001\U00000308\U0000094d", {1, 776}, {1, 6}}, {"\U00000001\U0000200d", {1, 8205}, {1, 4}}, {"\U00000001\U00000308\U0000200d", {1, 776}, {1, 6}}, {"\U00000001\U00000378", {1, 888}, {1, 3}}, {"\U00000001\U00000308\U00000378", {1, 776, 888}, {1, 3, 5}}, - {"\U0000034f\U00000020", {847, 32}, {2, 3}}, - {"\U0000034f\U00000308\U00000020", {847, 32}, {4, 5}}, - {"\U0000034f\U0000000d", {847, 13}, {2, 3}}, - {"\U0000034f\U00000308\U0000000d", {847, 13}, {4, 5}}, - {"\U0000034f\U0000000a", {847, 10}, {2, 3}}, - {"\U0000034f\U00000308\U0000000a", {847, 10}, {4, 5}}, - {"\U0000034f\U00000001", {847, 1}, {2, 3}}, - {"\U0000034f\U00000308\U00000001", {847, 1}, {4, 5}}, - {"\U0000034f\U0000034f", {847}, {4}}, - {"\U0000034f\U00000308\U0000034f", {847}, {6}}, - {"\U0000034f\U0001f1e6", {847, 127462}, {2, 6}}, - {"\U0000034f\U00000308\U0001f1e6", {847, 127462}, {4, 8}}, - {"\U0000034f\U00000600", {847, 1536}, {2, 4}}, - {"\U0000034f\U00000308\U00000600", {847, 1536}, {4, 6}}, - {"\U0000034f\U00000a03", {847}, {5}}, - {"\U0000034f\U00000308\U00000a03", {847}, {7}}, - {"\U0000034f\U00001100", {847, 4352}, {2, 5}}, - {"\U0000034f\U00000308\U00001100", {847, 4352}, {4, 7}}, - {"\U0000034f\U00001160", {847, 4448}, {2, 5}}, - {"\U0000034f\U00000308\U00001160", {847, 4448}, {4, 7}}, - {"\U0000034f\U000011a8", {847, 4520}, {2, 5}}, - {"\U0000034f\U00000308\U000011a8", {847, 4520}, {4, 7}}, - {"\U0000034f\U0000ac00", {847, 44032}, {2, 5}}, - {"\U0000034f\U00000308\U0000ac00", {847, 44032}, {4, 7}}, - {"\U0000034f\U0000ac01", {847, 44033}, {2, 5}}, - {"\U0000034f\U00000308\U0000ac01", {847, 44033}, {4, 7}}, - {"\U0000034f\U00000900", {847}, {5}}, - {"\U0000034f\U00000308\U00000900", {847}, {7}}, - {"\U0000034f\U00000903", {847}, {5}}, - {"\U0000034f\U00000308\U00000903", {847}, {7}}, - {"\U0000034f\U00000904", {847, 2308}, {2, 5}}, - {"\U0000034f\U00000308\U00000904", {847, 2308}, {4, 7}}, - {"\U0000034f\U00000d4e", {847, 3406}, {2, 5}}, - {"\U0000034f\U00000308\U00000d4e", {847, 3406}, {4, 7}}, - {"\U0000034f\U00000915", {847, 2325}, {2, 5}}, - {"\U0000034f\U00000308\U00000915", {847, 2325}, {4, 7}}, - {"\U0000034f\U0000231a", {847, 8986}, {2, 5}}, - {"\U0000034f\U00000308\U0000231a", {847, 8986}, {4, 7}}, - {"\U0000034f\U00000300", {847}, {4}}, - {"\U0000034f\U00000308\U00000300", {847}, {6}}, - {"\U0000034f\U0000093c", {847}, {5}}, - {"\U0000034f\U00000308\U0000093c", {847}, {7}}, - {"\U0000034f\U0000094d", {847}, {5}}, - {"\U0000034f\U00000308\U0000094d", {847}, {7}}, - {"\U0000034f\U0000200d", {847}, {5}}, - {"\U0000034f\U00000308\U0000200d", {847}, {7}}, - {"\U0000034f\U00000378", {847, 888}, {2, 4}}, - {"\U0000034f\U00000308\U00000378", {847, 888}, {4, 6}}, + {"\U0000200c\U00000020", {8204, 32}, {3, 4}}, + {"\U0000200c\U00000308\U00000020", {8204, 32}, {5, 6}}, + {"\U0000200c\U0000000d", {8204, 13}, {3, 4}}, + {"\U0000200c\U00000308\U0000000d", {8204, 13}, {5, 6}}, + {"\U0000200c\U0000000a", {8204, 10}, {3, 4}}, + {"\U0000200c\U00000308\U0000000a", {8204, 10}, {5, 6}}, + {"\U0000200c\U00000001", {8204, 1}, {3, 4}}, + {"\U0000200c\U00000308\U00000001", {8204, 1}, {5, 6}}, + {"\U0000200c\U0000200c", {8204}, {6}}, + {"\U0000200c\U00000308\U0000200c", {8204}, {8}}, + {"\U0000200c\U0001f1e6", {8204, 127462}, {3, 7}}, + {"\U0000200c\U00000308\U0001f1e6", {8204, 127462}, {5, 9}}, + {"\U0000200c\U00000600", {8204, 1536}, {3, 5}}, + {"\U0000200c\U00000308\U00000600", {8204, 1536}, {5, 7}}, + {"\U0000200c\U00000a03", {8204}, {6}}, + {"\U0000200c\U00000308\U00000a03", {8204}, {8}}, + {"\U0000200c\U00001100", {8204, 4352}, {3, 6}}, + {"\U0000200c\U00000308\U00001100", {8204, 4352}, {5, 8}}, + {"\U0000200c\U00001160", {8204, 4448}, {3, 6}}, + {"\U0000200c\U00000308\U00001160", {8204, 4448}, {5, 8}}, + {"\U0000200c\U000011a8", {8204, 4520}, {3, 6}}, + {"\U0000200c\U00000308\U000011a8", {8204, 4520}, {5, 8}}, + {"\U0000200c\U0000ac00", {8204, 44032}, {3, 6}}, + {"\U0000200c\U00000308\U0000ac00", {8204, 44032}, {5, 8}}, + {"\U0000200c\U0000ac01", {8204, 44033}, {3, 6}}, + {"\U0000200c\U00000308\U0000ac01", {8204, 44033}, {5, 8}}, + {"\U0000200c\U00000903", {8204}, {6}}, + {"\U0000200c\U00000308\U00000903", {8204}, {8}}, + {"\U0000200c\U00000904", {8204, 2308}, {3, 6}}, + {"\U0000200c\U00000308\U00000904", {8204, 2308}, {5, 8}}, + {"\U0000200c\U00000d4e", {8204, 3406}, {3, 6}}, + {"\U0000200c\U00000308\U00000d4e", {8204, 3406}, {5, 8}}, + {"\U0000200c\U00000915", {8204, 2325}, {3, 6}}, + {"\U0000200c\U00000308\U00000915", {8204, 2325}, {5, 8}}, + {"\U0000200c\U0000231a", {8204, 8986}, {3, 6}}, + {"\U0000200c\U00000308\U0000231a", {8204, 8986}, {5, 8}}, + {"\U0000200c\U00000300", {8204}, {5}}, + {"\U0000200c\U00000308\U00000300", {8204}, {7}}, + {"\U0000200c\U00000900", {8204}, {6}}, + {"\U0000200c\U00000308\U00000900", {8204}, {8}}, + {"\U0000200c\U0000094d", {8204}, {6}}, + {"\U0000200c\U00000308\U0000094d", {8204}, {8}}, + {"\U0000200c\U0000200d", {8204}, {6}}, + {"\U0000200c\U00000308\U0000200d", {8204}, {8}}, + {"\U0000200c\U00000378", {8204, 888}, {3, 5}}, + {"\U0000200c\U00000308\U00000378", {8204, 888}, {5, 7}}, {"\U0001f1e6\U00000020", {127462, 32}, {4, 5}}, {"\U0001f1e6\U00000308\U00000020", {127462, 32}, {6, 7}}, {"\U0001f1e6\U0000000d", {127462, 13}, {4, 5}}, @@ -331,8 +321,8 @@ std::array, 1187> data_utf8 = {{ {"\U0001f1e6\U00000308\U0000000a", {127462, 10}, {6, 7}}, {"\U0001f1e6\U00000001", {127462, 1}, {4, 5}}, {"\U0001f1e6\U00000308\U00000001", {127462, 1}, {6, 7}}, - {"\U0001f1e6\U0000034f", {127462}, {6}}, - {"\U0001f1e6\U00000308\U0000034f", {127462}, {8}}, + {"\U0001f1e6\U0000200c", {127462}, {7}}, + {"\U0001f1e6\U00000308\U0000200c", {127462}, {9}}, {"\U0001f1e6\U0001f1e6", {127462}, {8}}, {"\U0001f1e6\U00000308\U0001f1e6", {127462, 127462}, {6, 10}}, {"\U0001f1e6\U00000600", {127462, 1536}, {4, 6}}, @@ -349,8 +339,6 @@ std::array, 1187> data_utf8 = {{ {"\U0001f1e6\U00000308\U0000ac00", {127462, 44032}, {6, 9}}, {"\U0001f1e6\U0000ac01", {127462, 44033}, {4, 7}}, {"\U0001f1e6\U00000308\U0000ac01", {127462, 44033}, {6, 9}}, - {"\U0001f1e6\U00000900", {127462}, {7}}, - {"\U0001f1e6\U00000308\U00000900", {127462}, {9}}, {"\U0001f1e6\U00000903", {127462}, {7}}, {"\U0001f1e6\U00000308\U00000903", {127462}, {9}}, {"\U0001f1e6\U00000904", {127462, 2308}, {4, 7}}, @@ -363,8 +351,8 @@ std::array, 1187> data_utf8 = {{ {"\U0001f1e6\U00000308\U0000231a", {127462, 8986}, {6, 9}}, {"\U0001f1e6\U00000300", {127462}, {6}}, {"\U0001f1e6\U00000308\U00000300", {127462}, {8}}, - {"\U0001f1e6\U0000093c", {127462}, {7}}, - {"\U0001f1e6\U00000308\U0000093c", {127462}, {9}}, + {"\U0001f1e6\U00000900", {127462}, {7}}, + {"\U0001f1e6\U00000308\U00000900", {127462}, {9}}, {"\U0001f1e6\U0000094d", {127462}, {7}}, {"\U0001f1e6\U00000308\U0000094d", {127462}, {9}}, {"\U0001f1e6\U0000200d", {127462}, {7}}, @@ -379,8 +367,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000600\U00000308\U0000000a", {1536, 10}, {4, 5}}, {"\U00000600\U00000001", {1536, 1}, {2, 3}}, {"\U00000600\U00000308\U00000001", {1536, 1}, {4, 5}}, - {"\U00000600\U0000034f", {1536}, {4}}, - {"\U00000600\U00000308\U0000034f", {1536}, {6}}, + {"\U00000600\U0000200c", {1536}, {5}}, + {"\U00000600\U00000308\U0000200c", {1536}, {7}}, {"\U00000600\U0001f1e6", {1536}, {6}}, {"\U00000600\U00000308\U0001f1e6", {1536, 127462}, {4, 8}}, {"\U00000600\U00000600", {1536}, {4}}, @@ -397,8 +385,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000600\U00000308\U0000ac00", {1536, 44032}, {4, 7}}, {"\U00000600\U0000ac01", {1536}, {5}}, {"\U00000600\U00000308\U0000ac01", {1536, 44033}, {4, 7}}, - {"\U00000600\U00000900", {1536}, {5}}, - {"\U00000600\U00000308\U00000900", {1536}, {7}}, {"\U00000600\U00000903", {1536}, {5}}, {"\U00000600\U00000308\U00000903", {1536}, {7}}, {"\U00000600\U00000904", {1536}, {5}}, @@ -411,8 +397,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000600\U00000308\U0000231a", {1536, 8986}, {4, 7}}, {"\U00000600\U00000300", {1536}, {4}}, {"\U00000600\U00000308\U00000300", {1536}, {6}}, - {"\U00000600\U0000093c", {1536}, {5}}, - {"\U00000600\U00000308\U0000093c", {1536}, {7}}, + {"\U00000600\U00000900", {1536}, {5}}, + {"\U00000600\U00000308\U00000900", {1536}, {7}}, {"\U00000600\U0000094d", {1536}, {5}}, {"\U00000600\U00000308\U0000094d", {1536}, {7}}, {"\U00000600\U0000200d", {1536}, {5}}, @@ -427,8 +413,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000a03\U00000308\U0000000a", {2563, 10}, {5, 6}}, {"\U00000a03\U00000001", {2563, 1}, {3, 4}}, {"\U00000a03\U00000308\U00000001", {2563, 1}, {5, 6}}, - {"\U00000a03\U0000034f", {2563}, {5}}, - {"\U00000a03\U00000308\U0000034f", {2563}, {7}}, + {"\U00000a03\U0000200c", {2563}, {6}}, + {"\U00000a03\U00000308\U0000200c", {2563}, {8}}, {"\U00000a03\U0001f1e6", {2563, 127462}, {3, 7}}, {"\U00000a03\U00000308\U0001f1e6", {2563, 127462}, {5, 9}}, {"\U00000a03\U00000600", {2563, 1536}, {3, 5}}, @@ -445,8 +431,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000a03\U00000308\U0000ac00", {2563, 44032}, {5, 8}}, {"\U00000a03\U0000ac01", {2563, 44033}, {3, 6}}, {"\U00000a03\U00000308\U0000ac01", {2563, 44033}, {5, 8}}, - {"\U00000a03\U00000900", {2563}, {6}}, - {"\U00000a03\U00000308\U00000900", {2563}, {8}}, {"\U00000a03\U00000903", {2563}, {6}}, {"\U00000a03\U00000308\U00000903", {2563}, {8}}, {"\U00000a03\U00000904", {2563, 2308}, {3, 6}}, @@ -459,8 +443,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000a03\U00000308\U0000231a", {2563, 8986}, {5, 8}}, {"\U00000a03\U00000300", {2563}, {5}}, {"\U00000a03\U00000308\U00000300", {2563}, {7}}, - {"\U00000a03\U0000093c", {2563}, {6}}, - {"\U00000a03\U00000308\U0000093c", {2563}, {8}}, + {"\U00000a03\U00000900", {2563}, {6}}, + {"\U00000a03\U00000308\U00000900", {2563}, {8}}, {"\U00000a03\U0000094d", {2563}, {6}}, {"\U00000a03\U00000308\U0000094d", {2563}, {8}}, {"\U00000a03\U0000200d", {2563}, {6}}, @@ -475,8 +459,8 @@ std::array, 1187> data_utf8 = {{ {"\U00001100\U00000308\U0000000a", {4352, 10}, {5, 6}}, {"\U00001100\U00000001", {4352, 1}, {3, 4}}, {"\U00001100\U00000308\U00000001", {4352, 1}, {5, 6}}, - {"\U00001100\U0000034f", {4352}, {5}}, - {"\U00001100\U00000308\U0000034f", {4352}, {7}}, + {"\U00001100\U0000200c", {4352}, {6}}, + {"\U00001100\U00000308\U0000200c", {4352}, {8}}, {"\U00001100\U0001f1e6", {4352, 127462}, {3, 7}}, {"\U00001100\U00000308\U0001f1e6", {4352, 127462}, {5, 9}}, {"\U00001100\U00000600", {4352, 1536}, {3, 5}}, @@ -493,8 +477,6 @@ std::array, 1187> data_utf8 = {{ {"\U00001100\U00000308\U0000ac00", {4352, 44032}, {5, 8}}, {"\U00001100\U0000ac01", {4352}, {6}}, {"\U00001100\U00000308\U0000ac01", {4352, 44033}, {5, 8}}, - {"\U00001100\U00000900", {4352}, {6}}, - {"\U00001100\U00000308\U00000900", {4352}, {8}}, {"\U00001100\U00000903", {4352}, {6}}, {"\U00001100\U00000308\U00000903", {4352}, {8}}, {"\U00001100\U00000904", {4352, 2308}, {3, 6}}, @@ -507,8 +489,8 @@ std::array, 1187> data_utf8 = {{ {"\U00001100\U00000308\U0000231a", {4352, 8986}, {5, 8}}, {"\U00001100\U00000300", {4352}, {5}}, {"\U00001100\U00000308\U00000300", {4352}, {7}}, - {"\U00001100\U0000093c", {4352}, {6}}, - {"\U00001100\U00000308\U0000093c", {4352}, {8}}, + {"\U00001100\U00000900", {4352}, {6}}, + {"\U00001100\U00000308\U00000900", {4352}, {8}}, {"\U00001100\U0000094d", {4352}, {6}}, {"\U00001100\U00000308\U0000094d", {4352}, {8}}, {"\U00001100\U0000200d", {4352}, {6}}, @@ -523,8 +505,8 @@ std::array, 1187> data_utf8 = {{ {"\U00001160\U00000308\U0000000a", {4448, 10}, {5, 6}}, {"\U00001160\U00000001", {4448, 1}, {3, 4}}, {"\U00001160\U00000308\U00000001", {4448, 1}, {5, 6}}, - {"\U00001160\U0000034f", {4448}, {5}}, - {"\U00001160\U00000308\U0000034f", {4448}, {7}}, + {"\U00001160\U0000200c", {4448}, {6}}, + {"\U00001160\U00000308\U0000200c", {4448}, {8}}, {"\U00001160\U0001f1e6", {4448, 127462}, {3, 7}}, {"\U00001160\U00000308\U0001f1e6", {4448, 127462}, {5, 9}}, {"\U00001160\U00000600", {4448, 1536}, {3, 5}}, @@ -541,8 +523,6 @@ std::array, 1187> data_utf8 = {{ {"\U00001160\U00000308\U0000ac00", {4448, 44032}, {5, 8}}, {"\U00001160\U0000ac01", {4448, 44033}, {3, 6}}, {"\U00001160\U00000308\U0000ac01", {4448, 44033}, {5, 8}}, - {"\U00001160\U00000900", {4448}, {6}}, - {"\U00001160\U00000308\U00000900", {4448}, {8}}, {"\U00001160\U00000903", {4448}, {6}}, {"\U00001160\U00000308\U00000903", {4448}, {8}}, {"\U00001160\U00000904", {4448, 2308}, {3, 6}}, @@ -555,8 +535,8 @@ std::array, 1187> data_utf8 = {{ {"\U00001160\U00000308\U0000231a", {4448, 8986}, {5, 8}}, {"\U00001160\U00000300", {4448}, {5}}, {"\U00001160\U00000308\U00000300", {4448}, {7}}, - {"\U00001160\U0000093c", {4448}, {6}}, - {"\U00001160\U00000308\U0000093c", {4448}, {8}}, + {"\U00001160\U00000900", {4448}, {6}}, + {"\U00001160\U00000308\U00000900", {4448}, {8}}, {"\U00001160\U0000094d", {4448}, {6}}, {"\U00001160\U00000308\U0000094d", {4448}, {8}}, {"\U00001160\U0000200d", {4448}, {6}}, @@ -571,8 +551,8 @@ std::array, 1187> data_utf8 = {{ {"\U000011a8\U00000308\U0000000a", {4520, 10}, {5, 6}}, {"\U000011a8\U00000001", {4520, 1}, {3, 4}}, {"\U000011a8\U00000308\U00000001", {4520, 1}, {5, 6}}, - {"\U000011a8\U0000034f", {4520}, {5}}, - {"\U000011a8\U00000308\U0000034f", {4520}, {7}}, + {"\U000011a8\U0000200c", {4520}, {6}}, + {"\U000011a8\U00000308\U0000200c", {4520}, {8}}, {"\U000011a8\U0001f1e6", {4520, 127462}, {3, 7}}, {"\U000011a8\U00000308\U0001f1e6", {4520, 127462}, {5, 9}}, {"\U000011a8\U00000600", {4520, 1536}, {3, 5}}, @@ -589,8 +569,6 @@ std::array, 1187> data_utf8 = {{ {"\U000011a8\U00000308\U0000ac00", {4520, 44032}, {5, 8}}, {"\U000011a8\U0000ac01", {4520, 44033}, {3, 6}}, {"\U000011a8\U00000308\U0000ac01", {4520, 44033}, {5, 8}}, - {"\U000011a8\U00000900", {4520}, {6}}, - {"\U000011a8\U00000308\U00000900", {4520}, {8}}, {"\U000011a8\U00000903", {4520}, {6}}, {"\U000011a8\U00000308\U00000903", {4520}, {8}}, {"\U000011a8\U00000904", {4520, 2308}, {3, 6}}, @@ -603,8 +581,8 @@ std::array, 1187> data_utf8 = {{ {"\U000011a8\U00000308\U0000231a", {4520, 8986}, {5, 8}}, {"\U000011a8\U00000300", {4520}, {5}}, {"\U000011a8\U00000308\U00000300", {4520}, {7}}, - {"\U000011a8\U0000093c", {4520}, {6}}, - {"\U000011a8\U00000308\U0000093c", {4520}, {8}}, + {"\U000011a8\U00000900", {4520}, {6}}, + {"\U000011a8\U00000308\U00000900", {4520}, {8}}, {"\U000011a8\U0000094d", {4520}, {6}}, {"\U000011a8\U00000308\U0000094d", {4520}, {8}}, {"\U000011a8\U0000200d", {4520}, {6}}, @@ -619,8 +597,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac00\U00000308\U0000000a", {44032, 10}, {5, 6}}, {"\U0000ac00\U00000001", {44032, 1}, {3, 4}}, {"\U0000ac00\U00000308\U00000001", {44032, 1}, {5, 6}}, - {"\U0000ac00\U0000034f", {44032}, {5}}, - {"\U0000ac00\U00000308\U0000034f", {44032}, {7}}, + {"\U0000ac00\U0000200c", {44032}, {6}}, + {"\U0000ac00\U00000308\U0000200c", {44032}, {8}}, {"\U0000ac00\U0001f1e6", {44032, 127462}, {3, 7}}, {"\U0000ac00\U00000308\U0001f1e6", {44032, 127462}, {5, 9}}, {"\U0000ac00\U00000600", {44032, 1536}, {3, 5}}, @@ -637,8 +615,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac00\U00000308\U0000ac00", {44032, 44032}, {5, 8}}, {"\U0000ac00\U0000ac01", {44032, 44033}, {3, 6}}, {"\U0000ac00\U00000308\U0000ac01", {44032, 44033}, {5, 8}}, - {"\U0000ac00\U00000900", {44032}, {6}}, - {"\U0000ac00\U00000308\U00000900", {44032}, {8}}, {"\U0000ac00\U00000903", {44032}, {6}}, {"\U0000ac00\U00000308\U00000903", {44032}, {8}}, {"\U0000ac00\U00000904", {44032, 2308}, {3, 6}}, @@ -651,8 +627,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac00\U00000308\U0000231a", {44032, 8986}, {5, 8}}, {"\U0000ac00\U00000300", {44032}, {5}}, {"\U0000ac00\U00000308\U00000300", {44032}, {7}}, - {"\U0000ac00\U0000093c", {44032}, {6}}, - {"\U0000ac00\U00000308\U0000093c", {44032}, {8}}, + {"\U0000ac00\U00000900", {44032}, {6}}, + {"\U0000ac00\U00000308\U00000900", {44032}, {8}}, {"\U0000ac00\U0000094d", {44032}, {6}}, {"\U0000ac00\U00000308\U0000094d", {44032}, {8}}, {"\U0000ac00\U0000200d", {44032}, {6}}, @@ -667,8 +643,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac01\U00000308\U0000000a", {44033, 10}, {5, 6}}, {"\U0000ac01\U00000001", {44033, 1}, {3, 4}}, {"\U0000ac01\U00000308\U00000001", {44033, 1}, {5, 6}}, - {"\U0000ac01\U0000034f", {44033}, {5}}, - {"\U0000ac01\U00000308\U0000034f", {44033}, {7}}, + {"\U0000ac01\U0000200c", {44033}, {6}}, + {"\U0000ac01\U00000308\U0000200c", {44033}, {8}}, {"\U0000ac01\U0001f1e6", {44033, 127462}, {3, 7}}, {"\U0000ac01\U00000308\U0001f1e6", {44033, 127462}, {5, 9}}, {"\U0000ac01\U00000600", {44033, 1536}, {3, 5}}, @@ -685,8 +661,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac01\U00000308\U0000ac00", {44033, 44032}, {5, 8}}, {"\U0000ac01\U0000ac01", {44033, 44033}, {3, 6}}, {"\U0000ac01\U00000308\U0000ac01", {44033, 44033}, {5, 8}}, - {"\U0000ac01\U00000900", {44033}, {6}}, - {"\U0000ac01\U00000308\U00000900", {44033}, {8}}, {"\U0000ac01\U00000903", {44033}, {6}}, {"\U0000ac01\U00000308\U00000903", {44033}, {8}}, {"\U0000ac01\U00000904", {44033, 2308}, {3, 6}}, @@ -699,62 +673,14 @@ std::array, 1187> data_utf8 = {{ {"\U0000ac01\U00000308\U0000231a", {44033, 8986}, {5, 8}}, {"\U0000ac01\U00000300", {44033}, {5}}, {"\U0000ac01\U00000308\U00000300", {44033}, {7}}, - {"\U0000ac01\U0000093c", {44033}, {6}}, - {"\U0000ac01\U00000308\U0000093c", {44033}, {8}}, + {"\U0000ac01\U00000900", {44033}, {6}}, + {"\U0000ac01\U00000308\U00000900", {44033}, {8}}, {"\U0000ac01\U0000094d", {44033}, {6}}, {"\U0000ac01\U00000308\U0000094d", {44033}, {8}}, {"\U0000ac01\U0000200d", {44033}, {6}}, {"\U0000ac01\U00000308\U0000200d", {44033}, {8}}, {"\U0000ac01\U00000378", {44033, 888}, {3, 5}}, {"\U0000ac01\U00000308\U00000378", {44033, 888}, {5, 7}}, - {"\U00000900\U00000020", {2304, 32}, {3, 4}}, - {"\U00000900\U00000308\U00000020", {2304, 32}, {5, 6}}, - {"\U00000900\U0000000d", {2304, 13}, {3, 4}}, - {"\U00000900\U00000308\U0000000d", {2304, 13}, {5, 6}}, - {"\U00000900\U0000000a", {2304, 10}, {3, 4}}, - {"\U00000900\U00000308\U0000000a", {2304, 10}, {5, 6}}, - {"\U00000900\U00000001", {2304, 1}, {3, 4}}, - {"\U00000900\U00000308\U00000001", {2304, 1}, {5, 6}}, - {"\U00000900\U0000034f", {2304}, {5}}, - {"\U00000900\U00000308\U0000034f", {2304}, {7}}, - {"\U00000900\U0001f1e6", {2304, 127462}, {3, 7}}, - {"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {5, 9}}, - {"\U00000900\U00000600", {2304, 1536}, {3, 5}}, - {"\U00000900\U00000308\U00000600", {2304, 1536}, {5, 7}}, - {"\U00000900\U00000a03", {2304}, {6}}, - {"\U00000900\U00000308\U00000a03", {2304}, {8}}, - {"\U00000900\U00001100", {2304, 4352}, {3, 6}}, - {"\U00000900\U00000308\U00001100", {2304, 4352}, {5, 8}}, - {"\U00000900\U00001160", {2304, 4448}, {3, 6}}, - {"\U00000900\U00000308\U00001160", {2304, 4448}, {5, 8}}, - {"\U00000900\U000011a8", {2304, 4520}, {3, 6}}, - {"\U00000900\U00000308\U000011a8", {2304, 4520}, {5, 8}}, - {"\U00000900\U0000ac00", {2304, 44032}, {3, 6}}, - {"\U00000900\U00000308\U0000ac00", {2304, 44032}, {5, 8}}, - {"\U00000900\U0000ac01", {2304, 44033}, {3, 6}}, - {"\U00000900\U00000308\U0000ac01", {2304, 44033}, {5, 8}}, - {"\U00000900\U00000900", {2304}, {6}}, - {"\U00000900\U00000308\U00000900", {2304}, {8}}, - {"\U00000900\U00000903", {2304}, {6}}, - {"\U00000900\U00000308\U00000903", {2304}, {8}}, - {"\U00000900\U00000904", {2304, 2308}, {3, 6}}, - {"\U00000900\U00000308\U00000904", {2304, 2308}, {5, 8}}, - {"\U00000900\U00000d4e", {2304, 3406}, {3, 6}}, - {"\U00000900\U00000308\U00000d4e", {2304, 3406}, {5, 8}}, - {"\U00000900\U00000915", {2304, 2325}, {3, 6}}, - {"\U00000900\U00000308\U00000915", {2304, 2325}, {5, 8}}, - {"\U00000900\U0000231a", {2304, 8986}, {3, 6}}, - {"\U00000900\U00000308\U0000231a", {2304, 8986}, {5, 8}}, - {"\U00000900\U00000300", {2304}, {5}}, - {"\U00000900\U00000308\U00000300", {2304}, {7}}, - {"\U00000900\U0000093c", {2304}, {6}}, - {"\U00000900\U00000308\U0000093c", {2304}, {8}}, - {"\U00000900\U0000094d", {2304}, {6}}, - {"\U00000900\U00000308\U0000094d", {2304}, {8}}, - {"\U00000900\U0000200d", {2304}, {6}}, - {"\U00000900\U00000308\U0000200d", {2304}, {8}}, - {"\U00000900\U00000378", {2304, 888}, {3, 5}}, - {"\U00000900\U00000308\U00000378", {2304, 888}, {5, 7}}, {"\U00000903\U00000020", {2307, 32}, {3, 4}}, {"\U00000903\U00000308\U00000020", {2307, 32}, {5, 6}}, {"\U00000903\U0000000d", {2307, 13}, {3, 4}}, @@ -763,8 +689,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000903\U00000308\U0000000a", {2307, 10}, {5, 6}}, {"\U00000903\U00000001", {2307, 1}, {3, 4}}, {"\U00000903\U00000308\U00000001", {2307, 1}, {5, 6}}, - {"\U00000903\U0000034f", {2307}, {5}}, - {"\U00000903\U00000308\U0000034f", {2307}, {7}}, + {"\U00000903\U0000200c", {2307}, {6}}, + {"\U00000903\U00000308\U0000200c", {2307}, {8}}, {"\U00000903\U0001f1e6", {2307, 127462}, {3, 7}}, {"\U00000903\U00000308\U0001f1e6", {2307, 127462}, {5, 9}}, {"\U00000903\U00000600", {2307, 1536}, {3, 5}}, @@ -781,8 +707,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000903\U00000308\U0000ac00", {2307, 44032}, {5, 8}}, {"\U00000903\U0000ac01", {2307, 44033}, {3, 6}}, {"\U00000903\U00000308\U0000ac01", {2307, 44033}, {5, 8}}, - {"\U00000903\U00000900", {2307}, {6}}, - {"\U00000903\U00000308\U00000900", {2307}, {8}}, {"\U00000903\U00000903", {2307}, {6}}, {"\U00000903\U00000308\U00000903", {2307}, {8}}, {"\U00000903\U00000904", {2307, 2308}, {3, 6}}, @@ -795,8 +719,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000903\U00000308\U0000231a", {2307, 8986}, {5, 8}}, {"\U00000903\U00000300", {2307}, {5}}, {"\U00000903\U00000308\U00000300", {2307}, {7}}, - {"\U00000903\U0000093c", {2307}, {6}}, - {"\U00000903\U00000308\U0000093c", {2307}, {8}}, + {"\U00000903\U00000900", {2307}, {6}}, + {"\U00000903\U00000308\U00000900", {2307}, {8}}, {"\U00000903\U0000094d", {2307}, {6}}, {"\U00000903\U00000308\U0000094d", {2307}, {8}}, {"\U00000903\U0000200d", {2307}, {6}}, @@ -811,8 +735,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000904\U00000308\U0000000a", {2308, 10}, {5, 6}}, {"\U00000904\U00000001", {2308, 1}, {3, 4}}, {"\U00000904\U00000308\U00000001", {2308, 1}, {5, 6}}, - {"\U00000904\U0000034f", {2308}, {5}}, - {"\U00000904\U00000308\U0000034f", {2308}, {7}}, + {"\U00000904\U0000200c", {2308}, {6}}, + {"\U00000904\U00000308\U0000200c", {2308}, {8}}, {"\U00000904\U0001f1e6", {2308, 127462}, {3, 7}}, {"\U00000904\U00000308\U0001f1e6", {2308, 127462}, {5, 9}}, {"\U00000904\U00000600", {2308, 1536}, {3, 5}}, @@ -829,8 +753,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000904\U00000308\U0000ac00", {2308, 44032}, {5, 8}}, {"\U00000904\U0000ac01", {2308, 44033}, {3, 6}}, {"\U00000904\U00000308\U0000ac01", {2308, 44033}, {5, 8}}, - {"\U00000904\U00000900", {2308}, {6}}, - {"\U00000904\U00000308\U00000900", {2308}, {8}}, {"\U00000904\U00000903", {2308}, {6}}, {"\U00000904\U00000308\U00000903", {2308}, {8}}, {"\U00000904\U00000904", {2308, 2308}, {3, 6}}, @@ -843,8 +765,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000904\U00000308\U0000231a", {2308, 8986}, {5, 8}}, {"\U00000904\U00000300", {2308}, {5}}, {"\U00000904\U00000308\U00000300", {2308}, {7}}, - {"\U00000904\U0000093c", {2308}, {6}}, - {"\U00000904\U00000308\U0000093c", {2308}, {8}}, + {"\U00000904\U00000900", {2308}, {6}}, + {"\U00000904\U00000308\U00000900", {2308}, {8}}, {"\U00000904\U0000094d", {2308}, {6}}, {"\U00000904\U00000308\U0000094d", {2308}, {8}}, {"\U00000904\U0000200d", {2308}, {6}}, @@ -859,8 +781,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000d4e\U00000308\U0000000a", {3406, 10}, {5, 6}}, {"\U00000d4e\U00000001", {3406, 1}, {3, 4}}, {"\U00000d4e\U00000308\U00000001", {3406, 1}, {5, 6}}, - {"\U00000d4e\U0000034f", {3406}, {5}}, - {"\U00000d4e\U00000308\U0000034f", {3406}, {7}}, + {"\U00000d4e\U0000200c", {3406}, {6}}, + {"\U00000d4e\U00000308\U0000200c", {3406}, {8}}, {"\U00000d4e\U0001f1e6", {3406}, {7}}, {"\U00000d4e\U00000308\U0001f1e6", {3406, 127462}, {5, 9}}, {"\U00000d4e\U00000600", {3406}, {5}}, @@ -877,8 +799,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000d4e\U00000308\U0000ac00", {3406, 44032}, {5, 8}}, {"\U00000d4e\U0000ac01", {3406}, {6}}, {"\U00000d4e\U00000308\U0000ac01", {3406, 44033}, {5, 8}}, - {"\U00000d4e\U00000900", {3406}, {6}}, - {"\U00000d4e\U00000308\U00000900", {3406}, {8}}, {"\U00000d4e\U00000903", {3406}, {6}}, {"\U00000d4e\U00000308\U00000903", {3406}, {8}}, {"\U00000d4e\U00000904", {3406}, {6}}, @@ -891,8 +811,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000d4e\U00000308\U0000231a", {3406, 8986}, {5, 8}}, {"\U00000d4e\U00000300", {3406}, {5}}, {"\U00000d4e\U00000308\U00000300", {3406}, {7}}, - {"\U00000d4e\U0000093c", {3406}, {6}}, - {"\U00000d4e\U00000308\U0000093c", {3406}, {8}}, + {"\U00000d4e\U00000900", {3406}, {6}}, + {"\U00000d4e\U00000308\U00000900", {3406}, {8}}, {"\U00000d4e\U0000094d", {3406}, {6}}, {"\U00000d4e\U00000308\U0000094d", {3406}, {8}}, {"\U00000d4e\U0000200d", {3406}, {6}}, @@ -907,8 +827,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000915\U00000308\U0000000a", {2325, 10}, {5, 6}}, {"\U00000915\U00000001", {2325, 1}, {3, 4}}, {"\U00000915\U00000308\U00000001", {2325, 1}, {5, 6}}, - {"\U00000915\U0000034f", {2325}, {5}}, - {"\U00000915\U00000308\U0000034f", {2325}, {7}}, + {"\U00000915\U0000200c", {2325}, {6}}, + {"\U00000915\U00000308\U0000200c", {2325}, {8}}, {"\U00000915\U0001f1e6", {2325, 127462}, {3, 7}}, {"\U00000915\U00000308\U0001f1e6", {2325, 127462}, {5, 9}}, {"\U00000915\U00000600", {2325, 1536}, {3, 5}}, @@ -925,8 +845,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000915\U00000308\U0000ac00", {2325, 44032}, {5, 8}}, {"\U00000915\U0000ac01", {2325, 44033}, {3, 6}}, {"\U00000915\U00000308\U0000ac01", {2325, 44033}, {5, 8}}, - {"\U00000915\U00000900", {2325}, {6}}, - {"\U00000915\U00000308\U00000900", {2325}, {8}}, {"\U00000915\U00000903", {2325}, {6}}, {"\U00000915\U00000308\U00000903", {2325}, {8}}, {"\U00000915\U00000904", {2325, 2308}, {3, 6}}, @@ -939,8 +857,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000915\U00000308\U0000231a", {2325, 8986}, {5, 8}}, {"\U00000915\U00000300", {2325}, {5}}, {"\U00000915\U00000308\U00000300", {2325}, {7}}, - {"\U00000915\U0000093c", {2325}, {6}}, - {"\U00000915\U00000308\U0000093c", {2325}, {8}}, + {"\U00000915\U00000900", {2325}, {6}}, + {"\U00000915\U00000308\U00000900", {2325}, {8}}, {"\U00000915\U0000094d", {2325}, {6}}, {"\U00000915\U00000308\U0000094d", {2325}, {8}}, {"\U00000915\U0000200d", {2325}, {6}}, @@ -955,8 +873,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000231a\U00000308\U0000000a", {8986, 10}, {5, 6}}, {"\U0000231a\U00000001", {8986, 1}, {3, 4}}, {"\U0000231a\U00000308\U00000001", {8986, 1}, {5, 6}}, - {"\U0000231a\U0000034f", {8986}, {5}}, - {"\U0000231a\U00000308\U0000034f", {8986}, {7}}, + {"\U0000231a\U0000200c", {8986}, {6}}, + {"\U0000231a\U00000308\U0000200c", {8986}, {8}}, {"\U0000231a\U0001f1e6", {8986, 127462}, {3, 7}}, {"\U0000231a\U00000308\U0001f1e6", {8986, 127462}, {5, 9}}, {"\U0000231a\U00000600", {8986, 1536}, {3, 5}}, @@ -973,8 +891,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000231a\U00000308\U0000ac00", {8986, 44032}, {5, 8}}, {"\U0000231a\U0000ac01", {8986, 44033}, {3, 6}}, {"\U0000231a\U00000308\U0000ac01", {8986, 44033}, {5, 8}}, - {"\U0000231a\U00000900", {8986}, {6}}, - {"\U0000231a\U00000308\U00000900", {8986}, {8}}, {"\U0000231a\U00000903", {8986}, {6}}, {"\U0000231a\U00000308\U00000903", {8986}, {8}}, {"\U0000231a\U00000904", {8986, 2308}, {3, 6}}, @@ -987,8 +903,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000231a\U00000308\U0000231a", {8986, 8986}, {5, 8}}, {"\U0000231a\U00000300", {8986}, {5}}, {"\U0000231a\U00000308\U00000300", {8986}, {7}}, - {"\U0000231a\U0000093c", {8986}, {6}}, - {"\U0000231a\U00000308\U0000093c", {8986}, {8}}, + {"\U0000231a\U00000900", {8986}, {6}}, + {"\U0000231a\U00000308\U00000900", {8986}, {8}}, {"\U0000231a\U0000094d", {8986}, {6}}, {"\U0000231a\U00000308\U0000094d", {8986}, {8}}, {"\U0000231a\U0000200d", {8986}, {6}}, @@ -1003,8 +919,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000300\U00000308\U0000000a", {768, 10}, {4, 5}}, {"\U00000300\U00000001", {768, 1}, {2, 3}}, {"\U00000300\U00000308\U00000001", {768, 1}, {4, 5}}, - {"\U00000300\U0000034f", {768}, {4}}, - {"\U00000300\U00000308\U0000034f", {768}, {6}}, + {"\U00000300\U0000200c", {768}, {5}}, + {"\U00000300\U00000308\U0000200c", {768}, {7}}, {"\U00000300\U0001f1e6", {768, 127462}, {2, 6}}, {"\U00000300\U00000308\U0001f1e6", {768, 127462}, {4, 8}}, {"\U00000300\U00000600", {768, 1536}, {2, 4}}, @@ -1021,8 +937,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000300\U00000308\U0000ac00", {768, 44032}, {4, 7}}, {"\U00000300\U0000ac01", {768, 44033}, {2, 5}}, {"\U00000300\U00000308\U0000ac01", {768, 44033}, {4, 7}}, - {"\U00000300\U00000900", {768}, {5}}, - {"\U00000300\U00000308\U00000900", {768}, {7}}, {"\U00000300\U00000903", {768}, {5}}, {"\U00000300\U00000308\U00000903", {768}, {7}}, {"\U00000300\U00000904", {768, 2308}, {2, 5}}, @@ -1035,62 +949,60 @@ std::array, 1187> data_utf8 = {{ {"\U00000300\U00000308\U0000231a", {768, 8986}, {4, 7}}, {"\U00000300\U00000300", {768}, {4}}, {"\U00000300\U00000308\U00000300", {768}, {6}}, - {"\U00000300\U0000093c", {768}, {5}}, - {"\U00000300\U00000308\U0000093c", {768}, {7}}, + {"\U00000300\U00000900", {768}, {5}}, + {"\U00000300\U00000308\U00000900", {768}, {7}}, {"\U00000300\U0000094d", {768}, {5}}, {"\U00000300\U00000308\U0000094d", {768}, {7}}, {"\U00000300\U0000200d", {768}, {5}}, {"\U00000300\U00000308\U0000200d", {768}, {7}}, {"\U00000300\U00000378", {768, 888}, {2, 4}}, {"\U00000300\U00000308\U00000378", {768, 888}, {4, 6}}, - {"\U0000093c\U00000020", {2364, 32}, {3, 4}}, - {"\U0000093c\U00000308\U00000020", {2364, 32}, {5, 6}}, - {"\U0000093c\U0000000d", {2364, 13}, {3, 4}}, - {"\U0000093c\U00000308\U0000000d", {2364, 13}, {5, 6}}, - {"\U0000093c\U0000000a", {2364, 10}, {3, 4}}, - {"\U0000093c\U00000308\U0000000a", {2364, 10}, {5, 6}}, - {"\U0000093c\U00000001", {2364, 1}, {3, 4}}, - {"\U0000093c\U00000308\U00000001", {2364, 1}, {5, 6}}, - {"\U0000093c\U0000034f", {2364}, {5}}, - {"\U0000093c\U00000308\U0000034f", {2364}, {7}}, - {"\U0000093c\U0001f1e6", {2364, 127462}, {3, 7}}, - {"\U0000093c\U00000308\U0001f1e6", {2364, 127462}, {5, 9}}, - {"\U0000093c\U00000600", {2364, 1536}, {3, 5}}, - {"\U0000093c\U00000308\U00000600", {2364, 1536}, {5, 7}}, - {"\U0000093c\U00000a03", {2364}, {6}}, - {"\U0000093c\U00000308\U00000a03", {2364}, {8}}, - {"\U0000093c\U00001100", {2364, 4352}, {3, 6}}, - {"\U0000093c\U00000308\U00001100", {2364, 4352}, {5, 8}}, - {"\U0000093c\U00001160", {2364, 4448}, {3, 6}}, - {"\U0000093c\U00000308\U00001160", {2364, 4448}, {5, 8}}, - {"\U0000093c\U000011a8", {2364, 4520}, {3, 6}}, - {"\U0000093c\U00000308\U000011a8", {2364, 4520}, {5, 8}}, - {"\U0000093c\U0000ac00", {2364, 44032}, {3, 6}}, - {"\U0000093c\U00000308\U0000ac00", {2364, 44032}, {5, 8}}, - {"\U0000093c\U0000ac01", {2364, 44033}, {3, 6}}, - {"\U0000093c\U00000308\U0000ac01", {2364, 44033}, {5, 8}}, - {"\U0000093c\U00000900", {2364}, {6}}, - {"\U0000093c\U00000308\U00000900", {2364}, {8}}, - {"\U0000093c\U00000903", {2364}, {6}}, - {"\U0000093c\U00000308\U00000903", {2364}, {8}}, - {"\U0000093c\U00000904", {2364, 2308}, {3, 6}}, - {"\U0000093c\U00000308\U00000904", {2364, 2308}, {5, 8}}, - {"\U0000093c\U00000d4e", {2364, 3406}, {3, 6}}, - {"\U0000093c\U00000308\U00000d4e", {2364, 3406}, {5, 8}}, - {"\U0000093c\U00000915", {2364, 2325}, {3, 6}}, - {"\U0000093c\U00000308\U00000915", {2364, 2325}, {5, 8}}, - {"\U0000093c\U0000231a", {2364, 8986}, {3, 6}}, - {"\U0000093c\U00000308\U0000231a", {2364, 8986}, {5, 8}}, - {"\U0000093c\U00000300", {2364}, {5}}, - {"\U0000093c\U00000308\U00000300", {2364}, {7}}, - {"\U0000093c\U0000093c", {2364}, {6}}, - {"\U0000093c\U00000308\U0000093c", {2364}, {8}}, - {"\U0000093c\U0000094d", {2364}, {6}}, - {"\U0000093c\U00000308\U0000094d", {2364}, {8}}, - {"\U0000093c\U0000200d", {2364}, {6}}, - {"\U0000093c\U00000308\U0000200d", {2364}, {8}}, - {"\U0000093c\U00000378", {2364, 888}, {3, 5}}, - {"\U0000093c\U00000308\U00000378", {2364, 888}, {5, 7}}, + {"\U00000900\U00000020", {2304, 32}, {3, 4}}, + {"\U00000900\U00000308\U00000020", {2304, 32}, {5, 6}}, + {"\U00000900\U0000000d", {2304, 13}, {3, 4}}, + {"\U00000900\U00000308\U0000000d", {2304, 13}, {5, 6}}, + {"\U00000900\U0000000a", {2304, 10}, {3, 4}}, + {"\U00000900\U00000308\U0000000a", {2304, 10}, {5, 6}}, + {"\U00000900\U00000001", {2304, 1}, {3, 4}}, + {"\U00000900\U00000308\U00000001", {2304, 1}, {5, 6}}, + {"\U00000900\U0000200c", {2304}, {6}}, + {"\U00000900\U00000308\U0000200c", {2304}, {8}}, + {"\U00000900\U0001f1e6", {2304, 127462}, {3, 7}}, + {"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {5, 9}}, + {"\U00000900\U00000600", {2304, 1536}, {3, 5}}, + {"\U00000900\U00000308\U00000600", {2304, 1536}, {5, 7}}, + {"\U00000900\U00000a03", {2304}, {6}}, + {"\U00000900\U00000308\U00000a03", {2304}, {8}}, + {"\U00000900\U00001100", {2304, 4352}, {3, 6}}, + {"\U00000900\U00000308\U00001100", {2304, 4352}, {5, 8}}, + {"\U00000900\U00001160", {2304, 4448}, {3, 6}}, + {"\U00000900\U00000308\U00001160", {2304, 4448}, {5, 8}}, + {"\U00000900\U000011a8", {2304, 4520}, {3, 6}}, + {"\U00000900\U00000308\U000011a8", {2304, 4520}, {5, 8}}, + {"\U00000900\U0000ac00", {2304, 44032}, {3, 6}}, + {"\U00000900\U00000308\U0000ac00", {2304, 44032}, {5, 8}}, + {"\U00000900\U0000ac01", {2304, 44033}, {3, 6}}, + {"\U00000900\U00000308\U0000ac01", {2304, 44033}, {5, 8}}, + {"\U00000900\U00000903", {2304}, {6}}, + {"\U00000900\U00000308\U00000903", {2304}, {8}}, + {"\U00000900\U00000904", {2304, 2308}, {3, 6}}, + {"\U00000900\U00000308\U00000904", {2304, 2308}, {5, 8}}, + {"\U00000900\U00000d4e", {2304, 3406}, {3, 6}}, + {"\U00000900\U00000308\U00000d4e", {2304, 3406}, {5, 8}}, + {"\U00000900\U00000915", {2304, 2325}, {3, 6}}, + {"\U00000900\U00000308\U00000915", {2304, 2325}, {5, 8}}, + {"\U00000900\U0000231a", {2304, 8986}, {3, 6}}, + {"\U00000900\U00000308\U0000231a", {2304, 8986}, {5, 8}}, + {"\U00000900\U00000300", {2304}, {5}}, + {"\U00000900\U00000308\U00000300", {2304}, {7}}, + {"\U00000900\U00000900", {2304}, {6}}, + {"\U00000900\U00000308\U00000900", {2304}, {8}}, + {"\U00000900\U0000094d", {2304}, {6}}, + {"\U00000900\U00000308\U0000094d", {2304}, {8}}, + {"\U00000900\U0000200d", {2304}, {6}}, + {"\U00000900\U00000308\U0000200d", {2304}, {8}}, + {"\U00000900\U00000378", {2304, 888}, {3, 5}}, + {"\U00000900\U00000308\U00000378", {2304, 888}, {5, 7}}, {"\U0000094d\U00000020", {2381, 32}, {3, 4}}, {"\U0000094d\U00000308\U00000020", {2381, 32}, {5, 6}}, {"\U0000094d\U0000000d", {2381, 13}, {3, 4}}, @@ -1099,8 +1011,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000094d\U00000308\U0000000a", {2381, 10}, {5, 6}}, {"\U0000094d\U00000001", {2381, 1}, {3, 4}}, {"\U0000094d\U00000308\U00000001", {2381, 1}, {5, 6}}, - {"\U0000094d\U0000034f", {2381}, {5}}, - {"\U0000094d\U00000308\U0000034f", {2381}, {7}}, + {"\U0000094d\U0000200c", {2381}, {6}}, + {"\U0000094d\U00000308\U0000200c", {2381}, {8}}, {"\U0000094d\U0001f1e6", {2381, 127462}, {3, 7}}, {"\U0000094d\U00000308\U0001f1e6", {2381, 127462}, {5, 9}}, {"\U0000094d\U00000600", {2381, 1536}, {3, 5}}, @@ -1117,8 +1029,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000094d\U00000308\U0000ac00", {2381, 44032}, {5, 8}}, {"\U0000094d\U0000ac01", {2381, 44033}, {3, 6}}, {"\U0000094d\U00000308\U0000ac01", {2381, 44033}, {5, 8}}, - {"\U0000094d\U00000900", {2381}, {6}}, - {"\U0000094d\U00000308\U00000900", {2381}, {8}}, {"\U0000094d\U00000903", {2381}, {6}}, {"\U0000094d\U00000308\U00000903", {2381}, {8}}, {"\U0000094d\U00000904", {2381, 2308}, {3, 6}}, @@ -1131,8 +1041,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000094d\U00000308\U0000231a", {2381, 8986}, {5, 8}}, {"\U0000094d\U00000300", {2381}, {5}}, {"\U0000094d\U00000308\U00000300", {2381}, {7}}, - {"\U0000094d\U0000093c", {2381}, {6}}, - {"\U0000094d\U00000308\U0000093c", {2381}, {8}}, + {"\U0000094d\U00000900", {2381}, {6}}, + {"\U0000094d\U00000308\U00000900", {2381}, {8}}, {"\U0000094d\U0000094d", {2381}, {6}}, {"\U0000094d\U00000308\U0000094d", {2381}, {8}}, {"\U0000094d\U0000200d", {2381}, {6}}, @@ -1147,8 +1057,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000200d\U00000308\U0000000a", {8205, 10}, {5, 6}}, {"\U0000200d\U00000001", {8205, 1}, {3, 4}}, {"\U0000200d\U00000308\U00000001", {8205, 1}, {5, 6}}, - {"\U0000200d\U0000034f", {8205}, {5}}, - {"\U0000200d\U00000308\U0000034f", {8205}, {7}}, + {"\U0000200d\U0000200c", {8205}, {6}}, + {"\U0000200d\U00000308\U0000200c", {8205}, {8}}, {"\U0000200d\U0001f1e6", {8205, 127462}, {3, 7}}, {"\U0000200d\U00000308\U0001f1e6", {8205, 127462}, {5, 9}}, {"\U0000200d\U00000600", {8205, 1536}, {3, 5}}, @@ -1165,8 +1075,6 @@ std::array, 1187> data_utf8 = {{ {"\U0000200d\U00000308\U0000ac00", {8205, 44032}, {5, 8}}, {"\U0000200d\U0000ac01", {8205, 44033}, {3, 6}}, {"\U0000200d\U00000308\U0000ac01", {8205, 44033}, {5, 8}}, - {"\U0000200d\U00000900", {8205}, {6}}, - {"\U0000200d\U00000308\U00000900", {8205}, {8}}, {"\U0000200d\U00000903", {8205}, {6}}, {"\U0000200d\U00000308\U00000903", {8205}, {8}}, {"\U0000200d\U00000904", {8205, 2308}, {3, 6}}, @@ -1179,8 +1087,8 @@ std::array, 1187> data_utf8 = {{ {"\U0000200d\U00000308\U0000231a", {8205, 8986}, {5, 8}}, {"\U0000200d\U00000300", {8205}, {5}}, {"\U0000200d\U00000308\U00000300", {8205}, {7}}, - {"\U0000200d\U0000093c", {8205}, {6}}, - {"\U0000200d\U00000308\U0000093c", {8205}, {8}}, + {"\U0000200d\U00000900", {8205}, {6}}, + {"\U0000200d\U00000308\U00000900", {8205}, {8}}, {"\U0000200d\U0000094d", {8205}, {6}}, {"\U0000200d\U00000308\U0000094d", {8205}, {8}}, {"\U0000200d\U0000200d", {8205}, {6}}, @@ -1195,8 +1103,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000378\U00000308\U0000000a", {888, 10}, {4, 5}}, {"\U00000378\U00000001", {888, 1}, {2, 3}}, {"\U00000378\U00000308\U00000001", {888, 1}, {4, 5}}, - {"\U00000378\U0000034f", {888}, {4}}, - {"\U00000378\U00000308\U0000034f", {888}, {6}}, + {"\U00000378\U0000200c", {888}, {5}}, + {"\U00000378\U00000308\U0000200c", {888}, {7}}, {"\U00000378\U0001f1e6", {888, 127462}, {2, 6}}, {"\U00000378\U00000308\U0001f1e6", {888, 127462}, {4, 8}}, {"\U00000378\U00000600", {888, 1536}, {2, 4}}, @@ -1213,8 +1121,6 @@ std::array, 1187> data_utf8 = {{ {"\U00000378\U00000308\U0000ac00", {888, 44032}, {4, 7}}, {"\U00000378\U0000ac01", {888, 44033}, {2, 5}}, {"\U00000378\U00000308\U0000ac01", {888, 44033}, {4, 7}}, - {"\U00000378\U00000900", {888}, {5}}, - {"\U00000378\U00000308\U00000900", {888}, {7}}, {"\U00000378\U00000903", {888}, {5}}, {"\U00000378\U00000308\U00000903", {888}, {7}}, {"\U00000378\U00000904", {888, 2308}, {2, 5}}, @@ -1227,8 +1133,8 @@ std::array, 1187> data_utf8 = {{ {"\U00000378\U00000308\U0000231a", {888, 8986}, {4, 7}}, {"\U00000378\U00000300", {888}, {4}}, {"\U00000378\U00000308\U00000300", {888}, {6}}, - {"\U00000378\U0000093c", {888}, {5}}, - {"\U00000378\U00000308\U0000093c", {888}, {7}}, + {"\U00000378\U00000900", {888}, {5}}, + {"\U00000378\U00000308\U00000900", {888}, {7}}, {"\U00000378\U0000094d", {888}, {5}}, {"\U00000378\U00000308\U0000094d", {888}, {7}}, {"\U00000378\U0000200d", {888}, {5}}, @@ -1277,7 +1183,7 @@ std::array, 1187> data_utf8 = {{ /// since the size of the code units differ the breaks can contain different /// values. #ifndef TEST_HAS_NO_WIDE_CHARACTERS -std::array, 1187> data_utf16 = {{ +std::array, 1093> data_utf16 = {{ {L"\U00000020\U00000020", {32, 32}, {1, 2}}, {L"\U00000020\U00000308\U00000020", {32, 32}, {2, 3}}, {L"\U00000020\U0000000d", {32, 13}, {1, 2}}, @@ -1286,8 +1192,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000020\U00000308\U0000000a", {32, 10}, {2, 3}}, {L"\U00000020\U00000001", {32, 1}, {1, 2}}, {L"\U00000020\U00000308\U00000001", {32, 1}, {2, 3}}, - {L"\U00000020\U0000034f", {32}, {2}}, - {L"\U00000020\U00000308\U0000034f", {32}, {3}}, + {L"\U00000020\U0000200c", {32}, {2}}, + {L"\U00000020\U00000308\U0000200c", {32}, {3}}, {L"\U00000020\U0001f1e6", {32, 127462}, {1, 3}}, {L"\U00000020\U00000308\U0001f1e6", {32, 127462}, {2, 4}}, {L"\U00000020\U00000600", {32, 1536}, {1, 2}}, @@ -1304,8 +1210,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000020\U00000308\U0000ac00", {32, 44032}, {2, 3}}, {L"\U00000020\U0000ac01", {32, 44033}, {1, 2}}, {L"\U00000020\U00000308\U0000ac01", {32, 44033}, {2, 3}}, - {L"\U00000020\U00000900", {32}, {2}}, - {L"\U00000020\U00000308\U00000900", {32}, {3}}, {L"\U00000020\U00000903", {32}, {2}}, {L"\U00000020\U00000308\U00000903", {32}, {3}}, {L"\U00000020\U00000904", {32, 2308}, {1, 2}}, @@ -1318,8 +1222,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000020\U00000308\U0000231a", {32, 8986}, {2, 3}}, {L"\U00000020\U00000300", {32}, {2}}, {L"\U00000020\U00000308\U00000300", {32}, {3}}, - {L"\U00000020\U0000093c", {32}, {2}}, - {L"\U00000020\U00000308\U0000093c", {32}, {3}}, + {L"\U00000020\U00000900", {32}, {2}}, + {L"\U00000020\U00000308\U00000900", {32}, {3}}, {L"\U00000020\U0000094d", {32}, {2}}, {L"\U00000020\U00000308\U0000094d", {32}, {3}}, {L"\U00000020\U0000200d", {32}, {2}}, @@ -1334,8 +1238,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000d\U00000308\U0000000a", {13, 776, 10}, {1, 2, 3}}, {L"\U0000000d\U00000001", {13, 1}, {1, 2}}, {L"\U0000000d\U00000308\U00000001", {13, 776, 1}, {1, 2, 3}}, - {L"\U0000000d\U0000034f", {13, 847}, {1, 2}}, - {L"\U0000000d\U00000308\U0000034f", {13, 776}, {1, 3}}, + {L"\U0000000d\U0000200c", {13, 8204}, {1, 2}}, + {L"\U0000000d\U00000308\U0000200c", {13, 776}, {1, 3}}, {L"\U0000000d\U0001f1e6", {13, 127462}, {1, 3}}, {L"\U0000000d\U00000308\U0001f1e6", {13, 776, 127462}, {1, 2, 4}}, {L"\U0000000d\U00000600", {13, 1536}, {1, 2}}, @@ -1352,8 +1256,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000d\U00000308\U0000ac00", {13, 776, 44032}, {1, 2, 3}}, {L"\U0000000d\U0000ac01", {13, 44033}, {1, 2}}, {L"\U0000000d\U00000308\U0000ac01", {13, 776, 44033}, {1, 2, 3}}, - {L"\U0000000d\U00000900", {13, 2304}, {1, 2}}, - {L"\U0000000d\U00000308\U00000900", {13, 776}, {1, 3}}, {L"\U0000000d\U00000903", {13, 2307}, {1, 2}}, {L"\U0000000d\U00000308\U00000903", {13, 776}, {1, 3}}, {L"\U0000000d\U00000904", {13, 2308}, {1, 2}}, @@ -1366,8 +1268,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000d\U00000308\U0000231a", {13, 776, 8986}, {1, 2, 3}}, {L"\U0000000d\U00000300", {13, 768}, {1, 2}}, {L"\U0000000d\U00000308\U00000300", {13, 776}, {1, 3}}, - {L"\U0000000d\U0000093c", {13, 2364}, {1, 2}}, - {L"\U0000000d\U00000308\U0000093c", {13, 776}, {1, 3}}, + {L"\U0000000d\U00000900", {13, 2304}, {1, 2}}, + {L"\U0000000d\U00000308\U00000900", {13, 776}, {1, 3}}, {L"\U0000000d\U0000094d", {13, 2381}, {1, 2}}, {L"\U0000000d\U00000308\U0000094d", {13, 776}, {1, 3}}, {L"\U0000000d\U0000200d", {13, 8205}, {1, 2}}, @@ -1382,8 +1284,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000a\U00000308\U0000000a", {10, 776, 10}, {1, 2, 3}}, {L"\U0000000a\U00000001", {10, 1}, {1, 2}}, {L"\U0000000a\U00000308\U00000001", {10, 776, 1}, {1, 2, 3}}, - {L"\U0000000a\U0000034f", {10, 847}, {1, 2}}, - {L"\U0000000a\U00000308\U0000034f", {10, 776}, {1, 3}}, + {L"\U0000000a\U0000200c", {10, 8204}, {1, 2}}, + {L"\U0000000a\U00000308\U0000200c", {10, 776}, {1, 3}}, {L"\U0000000a\U0001f1e6", {10, 127462}, {1, 3}}, {L"\U0000000a\U00000308\U0001f1e6", {10, 776, 127462}, {1, 2, 4}}, {L"\U0000000a\U00000600", {10, 1536}, {1, 2}}, @@ -1400,8 +1302,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000a\U00000308\U0000ac00", {10, 776, 44032}, {1, 2, 3}}, {L"\U0000000a\U0000ac01", {10, 44033}, {1, 2}}, {L"\U0000000a\U00000308\U0000ac01", {10, 776, 44033}, {1, 2, 3}}, - {L"\U0000000a\U00000900", {10, 2304}, {1, 2}}, - {L"\U0000000a\U00000308\U00000900", {10, 776}, {1, 3}}, {L"\U0000000a\U00000903", {10, 2307}, {1, 2}}, {L"\U0000000a\U00000308\U00000903", {10, 776}, {1, 3}}, {L"\U0000000a\U00000904", {10, 2308}, {1, 2}}, @@ -1414,8 +1314,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000000a\U00000308\U0000231a", {10, 776, 8986}, {1, 2, 3}}, {L"\U0000000a\U00000300", {10, 768}, {1, 2}}, {L"\U0000000a\U00000308\U00000300", {10, 776}, {1, 3}}, - {L"\U0000000a\U0000093c", {10, 2364}, {1, 2}}, - {L"\U0000000a\U00000308\U0000093c", {10, 776}, {1, 3}}, + {L"\U0000000a\U00000900", {10, 2304}, {1, 2}}, + {L"\U0000000a\U00000308\U00000900", {10, 776}, {1, 3}}, {L"\U0000000a\U0000094d", {10, 2381}, {1, 2}}, {L"\U0000000a\U00000308\U0000094d", {10, 776}, {1, 3}}, {L"\U0000000a\U0000200d", {10, 8205}, {1, 2}}, @@ -1430,8 +1330,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000001\U00000308\U0000000a", {1, 776, 10}, {1, 2, 3}}, {L"\U00000001\U00000001", {1, 1}, {1, 2}}, {L"\U00000001\U00000308\U00000001", {1, 776, 1}, {1, 2, 3}}, - {L"\U00000001\U0000034f", {1, 847}, {1, 2}}, - {L"\U00000001\U00000308\U0000034f", {1, 776}, {1, 3}}, + {L"\U00000001\U0000200c", {1, 8204}, {1, 2}}, + {L"\U00000001\U00000308\U0000200c", {1, 776}, {1, 3}}, {L"\U00000001\U0001f1e6", {1, 127462}, {1, 3}}, {L"\U00000001\U00000308\U0001f1e6", {1, 776, 127462}, {1, 2, 4}}, {L"\U00000001\U00000600", {1, 1536}, {1, 2}}, @@ -1448,8 +1348,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000001\U00000308\U0000ac00", {1, 776, 44032}, {1, 2, 3}}, {L"\U00000001\U0000ac01", {1, 44033}, {1, 2}}, {L"\U00000001\U00000308\U0000ac01", {1, 776, 44033}, {1, 2, 3}}, - {L"\U00000001\U00000900", {1, 2304}, {1, 2}}, - {L"\U00000001\U00000308\U00000900", {1, 776}, {1, 3}}, {L"\U00000001\U00000903", {1, 2307}, {1, 2}}, {L"\U00000001\U00000308\U00000903", {1, 776}, {1, 3}}, {L"\U00000001\U00000904", {1, 2308}, {1, 2}}, @@ -1462,62 +1360,60 @@ std::array, 1187> data_utf16 = {{ {L"\U00000001\U00000308\U0000231a", {1, 776, 8986}, {1, 2, 3}}, {L"\U00000001\U00000300", {1, 768}, {1, 2}}, {L"\U00000001\U00000308\U00000300", {1, 776}, {1, 3}}, - {L"\U00000001\U0000093c", {1, 2364}, {1, 2}}, - {L"\U00000001\U00000308\U0000093c", {1, 776}, {1, 3}}, + {L"\U00000001\U00000900", {1, 2304}, {1, 2}}, + {L"\U00000001\U00000308\U00000900", {1, 776}, {1, 3}}, {L"\U00000001\U0000094d", {1, 2381}, {1, 2}}, {L"\U00000001\U00000308\U0000094d", {1, 776}, {1, 3}}, {L"\U00000001\U0000200d", {1, 8205}, {1, 2}}, {L"\U00000001\U00000308\U0000200d", {1, 776}, {1, 3}}, {L"\U00000001\U00000378", {1, 888}, {1, 2}}, {L"\U00000001\U00000308\U00000378", {1, 776, 888}, {1, 2, 3}}, - {L"\U0000034f\U00000020", {847, 32}, {1, 2}}, - {L"\U0000034f\U00000308\U00000020", {847, 32}, {2, 3}}, - {L"\U0000034f\U0000000d", {847, 13}, {1, 2}}, - {L"\U0000034f\U00000308\U0000000d", {847, 13}, {2, 3}}, - {L"\U0000034f\U0000000a", {847, 10}, {1, 2}}, - {L"\U0000034f\U00000308\U0000000a", {847, 10}, {2, 3}}, - {L"\U0000034f\U00000001", {847, 1}, {1, 2}}, - {L"\U0000034f\U00000308\U00000001", {847, 1}, {2, 3}}, - {L"\U0000034f\U0000034f", {847}, {2}}, - {L"\U0000034f\U00000308\U0000034f", {847}, {3}}, - {L"\U0000034f\U0001f1e6", {847, 127462}, {1, 3}}, - {L"\U0000034f\U00000308\U0001f1e6", {847, 127462}, {2, 4}}, - {L"\U0000034f\U00000600", {847, 1536}, {1, 2}}, - {L"\U0000034f\U00000308\U00000600", {847, 1536}, {2, 3}}, - {L"\U0000034f\U00000a03", {847}, {2}}, - {L"\U0000034f\U00000308\U00000a03", {847}, {3}}, - {L"\U0000034f\U00001100", {847, 4352}, {1, 2}}, - {L"\U0000034f\U00000308\U00001100", {847, 4352}, {2, 3}}, - {L"\U0000034f\U00001160", {847, 4448}, {1, 2}}, - {L"\U0000034f\U00000308\U00001160", {847, 4448}, {2, 3}}, - {L"\U0000034f\U000011a8", {847, 4520}, {1, 2}}, - {L"\U0000034f\U00000308\U000011a8", {847, 4520}, {2, 3}}, - {L"\U0000034f\U0000ac00", {847, 44032}, {1, 2}}, - {L"\U0000034f\U00000308\U0000ac00", {847, 44032}, {2, 3}}, - {L"\U0000034f\U0000ac01", {847, 44033}, {1, 2}}, - {L"\U0000034f\U00000308\U0000ac01", {847, 44033}, {2, 3}}, - {L"\U0000034f\U00000900", {847}, {2}}, - {L"\U0000034f\U00000308\U00000900", {847}, {3}}, - {L"\U0000034f\U00000903", {847}, {2}}, - {L"\U0000034f\U00000308\U00000903", {847}, {3}}, - {L"\U0000034f\U00000904", {847, 2308}, {1, 2}}, - {L"\U0000034f\U00000308\U00000904", {847, 2308}, {2, 3}}, - {L"\U0000034f\U00000d4e", {847, 3406}, {1, 2}}, - {L"\U0000034f\U00000308\U00000d4e", {847, 3406}, {2, 3}}, - {L"\U0000034f\U00000915", {847, 2325}, {1, 2}}, - {L"\U0000034f\U00000308\U00000915", {847, 2325}, {2, 3}}, - {L"\U0000034f\U0000231a", {847, 8986}, {1, 2}}, - {L"\U0000034f\U00000308\U0000231a", {847, 8986}, {2, 3}}, - {L"\U0000034f\U00000300", {847}, {2}}, - {L"\U0000034f\U00000308\U00000300", {847}, {3}}, - {L"\U0000034f\U0000093c", {847}, {2}}, - {L"\U0000034f\U00000308\U0000093c", {847}, {3}}, - {L"\U0000034f\U0000094d", {847}, {2}}, - {L"\U0000034f\U00000308\U0000094d", {847}, {3}}, - {L"\U0000034f\U0000200d", {847}, {2}}, - {L"\U0000034f\U00000308\U0000200d", {847}, {3}}, - {L"\U0000034f\U00000378", {847, 888}, {1, 2}}, - {L"\U0000034f\U00000308\U00000378", {847, 888}, {2, 3}}, + {L"\U0000200c\U00000020", {8204, 32}, {1, 2}}, + {L"\U0000200c\U00000308\U00000020", {8204, 32}, {2, 3}}, + {L"\U0000200c\U0000000d", {8204, 13}, {1, 2}}, + {L"\U0000200c\U00000308\U0000000d", {8204, 13}, {2, 3}}, + {L"\U0000200c\U0000000a", {8204, 10}, {1, 2}}, + {L"\U0000200c\U00000308\U0000000a", {8204, 10}, {2, 3}}, + {L"\U0000200c\U00000001", {8204, 1}, {1, 2}}, + {L"\U0000200c\U00000308\U00000001", {8204, 1}, {2, 3}}, + {L"\U0000200c\U0000200c", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000200c", {8204}, {3}}, + {L"\U0000200c\U0001f1e6", {8204, 127462}, {1, 3}}, + {L"\U0000200c\U00000308\U0001f1e6", {8204, 127462}, {2, 4}}, + {L"\U0000200c\U00000600", {8204, 1536}, {1, 2}}, + {L"\U0000200c\U00000308\U00000600", {8204, 1536}, {2, 3}}, + {L"\U0000200c\U00000a03", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000a03", {8204}, {3}}, + {L"\U0000200c\U00001100", {8204, 4352}, {1, 2}}, + {L"\U0000200c\U00000308\U00001100", {8204, 4352}, {2, 3}}, + {L"\U0000200c\U00001160", {8204, 4448}, {1, 2}}, + {L"\U0000200c\U00000308\U00001160", {8204, 4448}, {2, 3}}, + {L"\U0000200c\U000011a8", {8204, 4520}, {1, 2}}, + {L"\U0000200c\U00000308\U000011a8", {8204, 4520}, {2, 3}}, + {L"\U0000200c\U0000ac00", {8204, 44032}, {1, 2}}, + {L"\U0000200c\U00000308\U0000ac00", {8204, 44032}, {2, 3}}, + {L"\U0000200c\U0000ac01", {8204, 44033}, {1, 2}}, + {L"\U0000200c\U00000308\U0000ac01", {8204, 44033}, {2, 3}}, + {L"\U0000200c\U00000903", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000903", {8204}, {3}}, + {L"\U0000200c\U00000904", {8204, 2308}, {1, 2}}, + {L"\U0000200c\U00000308\U00000904", {8204, 2308}, {2, 3}}, + {L"\U0000200c\U00000d4e", {8204, 3406}, {1, 2}}, + {L"\U0000200c\U00000308\U00000d4e", {8204, 3406}, {2, 3}}, + {L"\U0000200c\U00000915", {8204, 2325}, {1, 2}}, + {L"\U0000200c\U00000308\U00000915", {8204, 2325}, {2, 3}}, + {L"\U0000200c\U0000231a", {8204, 8986}, {1, 2}}, + {L"\U0000200c\U00000308\U0000231a", {8204, 8986}, {2, 3}}, + {L"\U0000200c\U00000300", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000300", {8204}, {3}}, + {L"\U0000200c\U00000900", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000900", {8204}, {3}}, + {L"\U0000200c\U0000094d", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000094d", {8204}, {3}}, + {L"\U0000200c\U0000200d", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000200d", {8204}, {3}}, + {L"\U0000200c\U00000378", {8204, 888}, {1, 2}}, + {L"\U0000200c\U00000308\U00000378", {8204, 888}, {2, 3}}, {L"\U0001f1e6\U00000020", {127462, 32}, {2, 3}}, {L"\U0001f1e6\U00000308\U00000020", {127462, 32}, {3, 4}}, {L"\U0001f1e6\U0000000d", {127462, 13}, {2, 3}}, @@ -1526,8 +1422,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0001f1e6\U00000308\U0000000a", {127462, 10}, {3, 4}}, {L"\U0001f1e6\U00000001", {127462, 1}, {2, 3}}, {L"\U0001f1e6\U00000308\U00000001", {127462, 1}, {3, 4}}, - {L"\U0001f1e6\U0000034f", {127462}, {3}}, - {L"\U0001f1e6\U00000308\U0000034f", {127462}, {4}}, + {L"\U0001f1e6\U0000200c", {127462}, {3}}, + {L"\U0001f1e6\U00000308\U0000200c", {127462}, {4}}, {L"\U0001f1e6\U0001f1e6", {127462}, {4}}, {L"\U0001f1e6\U00000308\U0001f1e6", {127462, 127462}, {3, 5}}, {L"\U0001f1e6\U00000600", {127462, 1536}, {2, 3}}, @@ -1544,8 +1440,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0001f1e6\U00000308\U0000ac00", {127462, 44032}, {3, 4}}, {L"\U0001f1e6\U0000ac01", {127462, 44033}, {2, 3}}, {L"\U0001f1e6\U00000308\U0000ac01", {127462, 44033}, {3, 4}}, - {L"\U0001f1e6\U00000900", {127462}, {3}}, - {L"\U0001f1e6\U00000308\U00000900", {127462}, {4}}, {L"\U0001f1e6\U00000903", {127462}, {3}}, {L"\U0001f1e6\U00000308\U00000903", {127462}, {4}}, {L"\U0001f1e6\U00000904", {127462, 2308}, {2, 3}}, @@ -1558,8 +1452,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0001f1e6\U00000308\U0000231a", {127462, 8986}, {3, 4}}, {L"\U0001f1e6\U00000300", {127462}, {3}}, {L"\U0001f1e6\U00000308\U00000300", {127462}, {4}}, - {L"\U0001f1e6\U0000093c", {127462}, {3}}, - {L"\U0001f1e6\U00000308\U0000093c", {127462}, {4}}, + {L"\U0001f1e6\U00000900", {127462}, {3}}, + {L"\U0001f1e6\U00000308\U00000900", {127462}, {4}}, {L"\U0001f1e6\U0000094d", {127462}, {3}}, {L"\U0001f1e6\U00000308\U0000094d", {127462}, {4}}, {L"\U0001f1e6\U0000200d", {127462}, {3}}, @@ -1574,8 +1468,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000600\U00000308\U0000000a", {1536, 10}, {2, 3}}, {L"\U00000600\U00000001", {1536, 1}, {1, 2}}, {L"\U00000600\U00000308\U00000001", {1536, 1}, {2, 3}}, - {L"\U00000600\U0000034f", {1536}, {2}}, - {L"\U00000600\U00000308\U0000034f", {1536}, {3}}, + {L"\U00000600\U0000200c", {1536}, {2}}, + {L"\U00000600\U00000308\U0000200c", {1536}, {3}}, {L"\U00000600\U0001f1e6", {1536}, {3}}, {L"\U00000600\U00000308\U0001f1e6", {1536, 127462}, {2, 4}}, {L"\U00000600\U00000600", {1536}, {2}}, @@ -1592,8 +1486,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000600\U00000308\U0000ac00", {1536, 44032}, {2, 3}}, {L"\U00000600\U0000ac01", {1536}, {2}}, {L"\U00000600\U00000308\U0000ac01", {1536, 44033}, {2, 3}}, - {L"\U00000600\U00000900", {1536}, {2}}, - {L"\U00000600\U00000308\U00000900", {1536}, {3}}, {L"\U00000600\U00000903", {1536}, {2}}, {L"\U00000600\U00000308\U00000903", {1536}, {3}}, {L"\U00000600\U00000904", {1536}, {2}}, @@ -1606,8 +1498,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000600\U00000308\U0000231a", {1536, 8986}, {2, 3}}, {L"\U00000600\U00000300", {1536}, {2}}, {L"\U00000600\U00000308\U00000300", {1536}, {3}}, - {L"\U00000600\U0000093c", {1536}, {2}}, - {L"\U00000600\U00000308\U0000093c", {1536}, {3}}, + {L"\U00000600\U00000900", {1536}, {2}}, + {L"\U00000600\U00000308\U00000900", {1536}, {3}}, {L"\U00000600\U0000094d", {1536}, {2}}, {L"\U00000600\U00000308\U0000094d", {1536}, {3}}, {L"\U00000600\U0000200d", {1536}, {2}}, @@ -1622,8 +1514,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000a03\U00000308\U0000000a", {2563, 10}, {2, 3}}, {L"\U00000a03\U00000001", {2563, 1}, {1, 2}}, {L"\U00000a03\U00000308\U00000001", {2563, 1}, {2, 3}}, - {L"\U00000a03\U0000034f", {2563}, {2}}, - {L"\U00000a03\U00000308\U0000034f", {2563}, {3}}, + {L"\U00000a03\U0000200c", {2563}, {2}}, + {L"\U00000a03\U00000308\U0000200c", {2563}, {3}}, {L"\U00000a03\U0001f1e6", {2563, 127462}, {1, 3}}, {L"\U00000a03\U00000308\U0001f1e6", {2563, 127462}, {2, 4}}, {L"\U00000a03\U00000600", {2563, 1536}, {1, 2}}, @@ -1640,8 +1532,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000a03\U00000308\U0000ac00", {2563, 44032}, {2, 3}}, {L"\U00000a03\U0000ac01", {2563, 44033}, {1, 2}}, {L"\U00000a03\U00000308\U0000ac01", {2563, 44033}, {2, 3}}, - {L"\U00000a03\U00000900", {2563}, {2}}, - {L"\U00000a03\U00000308\U00000900", {2563}, {3}}, {L"\U00000a03\U00000903", {2563}, {2}}, {L"\U00000a03\U00000308\U00000903", {2563}, {3}}, {L"\U00000a03\U00000904", {2563, 2308}, {1, 2}}, @@ -1654,8 +1544,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000a03\U00000308\U0000231a", {2563, 8986}, {2, 3}}, {L"\U00000a03\U00000300", {2563}, {2}}, {L"\U00000a03\U00000308\U00000300", {2563}, {3}}, - {L"\U00000a03\U0000093c", {2563}, {2}}, - {L"\U00000a03\U00000308\U0000093c", {2563}, {3}}, + {L"\U00000a03\U00000900", {2563}, {2}}, + {L"\U00000a03\U00000308\U00000900", {2563}, {3}}, {L"\U00000a03\U0000094d", {2563}, {2}}, {L"\U00000a03\U00000308\U0000094d", {2563}, {3}}, {L"\U00000a03\U0000200d", {2563}, {2}}, @@ -1670,8 +1560,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00001100\U00000308\U0000000a", {4352, 10}, {2, 3}}, {L"\U00001100\U00000001", {4352, 1}, {1, 2}}, {L"\U00001100\U00000308\U00000001", {4352, 1}, {2, 3}}, - {L"\U00001100\U0000034f", {4352}, {2}}, - {L"\U00001100\U00000308\U0000034f", {4352}, {3}}, + {L"\U00001100\U0000200c", {4352}, {2}}, + {L"\U00001100\U00000308\U0000200c", {4352}, {3}}, {L"\U00001100\U0001f1e6", {4352, 127462}, {1, 3}}, {L"\U00001100\U00000308\U0001f1e6", {4352, 127462}, {2, 4}}, {L"\U00001100\U00000600", {4352, 1536}, {1, 2}}, @@ -1688,8 +1578,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00001100\U00000308\U0000ac00", {4352, 44032}, {2, 3}}, {L"\U00001100\U0000ac01", {4352}, {2}}, {L"\U00001100\U00000308\U0000ac01", {4352, 44033}, {2, 3}}, - {L"\U00001100\U00000900", {4352}, {2}}, - {L"\U00001100\U00000308\U00000900", {4352}, {3}}, {L"\U00001100\U00000903", {4352}, {2}}, {L"\U00001100\U00000308\U00000903", {4352}, {3}}, {L"\U00001100\U00000904", {4352, 2308}, {1, 2}}, @@ -1702,8 +1590,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00001100\U00000308\U0000231a", {4352, 8986}, {2, 3}}, {L"\U00001100\U00000300", {4352}, {2}}, {L"\U00001100\U00000308\U00000300", {4352}, {3}}, - {L"\U00001100\U0000093c", {4352}, {2}}, - {L"\U00001100\U00000308\U0000093c", {4352}, {3}}, + {L"\U00001100\U00000900", {4352}, {2}}, + {L"\U00001100\U00000308\U00000900", {4352}, {3}}, {L"\U00001100\U0000094d", {4352}, {2}}, {L"\U00001100\U00000308\U0000094d", {4352}, {3}}, {L"\U00001100\U0000200d", {4352}, {2}}, @@ -1718,8 +1606,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00001160\U00000308\U0000000a", {4448, 10}, {2, 3}}, {L"\U00001160\U00000001", {4448, 1}, {1, 2}}, {L"\U00001160\U00000308\U00000001", {4448, 1}, {2, 3}}, - {L"\U00001160\U0000034f", {4448}, {2}}, - {L"\U00001160\U00000308\U0000034f", {4448}, {3}}, + {L"\U00001160\U0000200c", {4448}, {2}}, + {L"\U00001160\U00000308\U0000200c", {4448}, {3}}, {L"\U00001160\U0001f1e6", {4448, 127462}, {1, 3}}, {L"\U00001160\U00000308\U0001f1e6", {4448, 127462}, {2, 4}}, {L"\U00001160\U00000600", {4448, 1536}, {1, 2}}, @@ -1736,8 +1624,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00001160\U00000308\U0000ac00", {4448, 44032}, {2, 3}}, {L"\U00001160\U0000ac01", {4448, 44033}, {1, 2}}, {L"\U00001160\U00000308\U0000ac01", {4448, 44033}, {2, 3}}, - {L"\U00001160\U00000900", {4448}, {2}}, - {L"\U00001160\U00000308\U00000900", {4448}, {3}}, {L"\U00001160\U00000903", {4448}, {2}}, {L"\U00001160\U00000308\U00000903", {4448}, {3}}, {L"\U00001160\U00000904", {4448, 2308}, {1, 2}}, @@ -1750,8 +1636,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00001160\U00000308\U0000231a", {4448, 8986}, {2, 3}}, {L"\U00001160\U00000300", {4448}, {2}}, {L"\U00001160\U00000308\U00000300", {4448}, {3}}, - {L"\U00001160\U0000093c", {4448}, {2}}, - {L"\U00001160\U00000308\U0000093c", {4448}, {3}}, + {L"\U00001160\U00000900", {4448}, {2}}, + {L"\U00001160\U00000308\U00000900", {4448}, {3}}, {L"\U00001160\U0000094d", {4448}, {2}}, {L"\U00001160\U00000308\U0000094d", {4448}, {3}}, {L"\U00001160\U0000200d", {4448}, {2}}, @@ -1766,8 +1652,8 @@ std::array, 1187> data_utf16 = {{ {L"\U000011a8\U00000308\U0000000a", {4520, 10}, {2, 3}}, {L"\U000011a8\U00000001", {4520, 1}, {1, 2}}, {L"\U000011a8\U00000308\U00000001", {4520, 1}, {2, 3}}, - {L"\U000011a8\U0000034f", {4520}, {2}}, - {L"\U000011a8\U00000308\U0000034f", {4520}, {3}}, + {L"\U000011a8\U0000200c", {4520}, {2}}, + {L"\U000011a8\U00000308\U0000200c", {4520}, {3}}, {L"\U000011a8\U0001f1e6", {4520, 127462}, {1, 3}}, {L"\U000011a8\U00000308\U0001f1e6", {4520, 127462}, {2, 4}}, {L"\U000011a8\U00000600", {4520, 1536}, {1, 2}}, @@ -1784,8 +1670,6 @@ std::array, 1187> data_utf16 = {{ {L"\U000011a8\U00000308\U0000ac00", {4520, 44032}, {2, 3}}, {L"\U000011a8\U0000ac01", {4520, 44033}, {1, 2}}, {L"\U000011a8\U00000308\U0000ac01", {4520, 44033}, {2, 3}}, - {L"\U000011a8\U00000900", {4520}, {2}}, - {L"\U000011a8\U00000308\U00000900", {4520}, {3}}, {L"\U000011a8\U00000903", {4520}, {2}}, {L"\U000011a8\U00000308\U00000903", {4520}, {3}}, {L"\U000011a8\U00000904", {4520, 2308}, {1, 2}}, @@ -1798,8 +1682,8 @@ std::array, 1187> data_utf16 = {{ {L"\U000011a8\U00000308\U0000231a", {4520, 8986}, {2, 3}}, {L"\U000011a8\U00000300", {4520}, {2}}, {L"\U000011a8\U00000308\U00000300", {4520}, {3}}, - {L"\U000011a8\U0000093c", {4520}, {2}}, - {L"\U000011a8\U00000308\U0000093c", {4520}, {3}}, + {L"\U000011a8\U00000900", {4520}, {2}}, + {L"\U000011a8\U00000308\U00000900", {4520}, {3}}, {L"\U000011a8\U0000094d", {4520}, {2}}, {L"\U000011a8\U00000308\U0000094d", {4520}, {3}}, {L"\U000011a8\U0000200d", {4520}, {2}}, @@ -1814,8 +1698,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac00\U00000308\U0000000a", {44032, 10}, {2, 3}}, {L"\U0000ac00\U00000001", {44032, 1}, {1, 2}}, {L"\U0000ac00\U00000308\U00000001", {44032, 1}, {2, 3}}, - {L"\U0000ac00\U0000034f", {44032}, {2}}, - {L"\U0000ac00\U00000308\U0000034f", {44032}, {3}}, + {L"\U0000ac00\U0000200c", {44032}, {2}}, + {L"\U0000ac00\U00000308\U0000200c", {44032}, {3}}, {L"\U0000ac00\U0001f1e6", {44032, 127462}, {1, 3}}, {L"\U0000ac00\U00000308\U0001f1e6", {44032, 127462}, {2, 4}}, {L"\U0000ac00\U00000600", {44032, 1536}, {1, 2}}, @@ -1832,8 +1716,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac00\U00000308\U0000ac00", {44032, 44032}, {2, 3}}, {L"\U0000ac00\U0000ac01", {44032, 44033}, {1, 2}}, {L"\U0000ac00\U00000308\U0000ac01", {44032, 44033}, {2, 3}}, - {L"\U0000ac00\U00000900", {44032}, {2}}, - {L"\U0000ac00\U00000308\U00000900", {44032}, {3}}, {L"\U0000ac00\U00000903", {44032}, {2}}, {L"\U0000ac00\U00000308\U00000903", {44032}, {3}}, {L"\U0000ac00\U00000904", {44032, 2308}, {1, 2}}, @@ -1846,8 +1728,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac00\U00000308\U0000231a", {44032, 8986}, {2, 3}}, {L"\U0000ac00\U00000300", {44032}, {2}}, {L"\U0000ac00\U00000308\U00000300", {44032}, {3}}, - {L"\U0000ac00\U0000093c", {44032}, {2}}, - {L"\U0000ac00\U00000308\U0000093c", {44032}, {3}}, + {L"\U0000ac00\U00000900", {44032}, {2}}, + {L"\U0000ac00\U00000308\U00000900", {44032}, {3}}, {L"\U0000ac00\U0000094d", {44032}, {2}}, {L"\U0000ac00\U00000308\U0000094d", {44032}, {3}}, {L"\U0000ac00\U0000200d", {44032}, {2}}, @@ -1862,8 +1744,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac01\U00000308\U0000000a", {44033, 10}, {2, 3}}, {L"\U0000ac01\U00000001", {44033, 1}, {1, 2}}, {L"\U0000ac01\U00000308\U00000001", {44033, 1}, {2, 3}}, - {L"\U0000ac01\U0000034f", {44033}, {2}}, - {L"\U0000ac01\U00000308\U0000034f", {44033}, {3}}, + {L"\U0000ac01\U0000200c", {44033}, {2}}, + {L"\U0000ac01\U00000308\U0000200c", {44033}, {3}}, {L"\U0000ac01\U0001f1e6", {44033, 127462}, {1, 3}}, {L"\U0000ac01\U00000308\U0001f1e6", {44033, 127462}, {2, 4}}, {L"\U0000ac01\U00000600", {44033, 1536}, {1, 2}}, @@ -1880,8 +1762,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac01\U00000308\U0000ac00", {44033, 44032}, {2, 3}}, {L"\U0000ac01\U0000ac01", {44033, 44033}, {1, 2}}, {L"\U0000ac01\U00000308\U0000ac01", {44033, 44033}, {2, 3}}, - {L"\U0000ac01\U00000900", {44033}, {2}}, - {L"\U0000ac01\U00000308\U00000900", {44033}, {3}}, {L"\U0000ac01\U00000903", {44033}, {2}}, {L"\U0000ac01\U00000308\U00000903", {44033}, {3}}, {L"\U0000ac01\U00000904", {44033, 2308}, {1, 2}}, @@ -1894,62 +1774,14 @@ std::array, 1187> data_utf16 = {{ {L"\U0000ac01\U00000308\U0000231a", {44033, 8986}, {2, 3}}, {L"\U0000ac01\U00000300", {44033}, {2}}, {L"\U0000ac01\U00000308\U00000300", {44033}, {3}}, - {L"\U0000ac01\U0000093c", {44033}, {2}}, - {L"\U0000ac01\U00000308\U0000093c", {44033}, {3}}, + {L"\U0000ac01\U00000900", {44033}, {2}}, + {L"\U0000ac01\U00000308\U00000900", {44033}, {3}}, {L"\U0000ac01\U0000094d", {44033}, {2}}, {L"\U0000ac01\U00000308\U0000094d", {44033}, {3}}, {L"\U0000ac01\U0000200d", {44033}, {2}}, {L"\U0000ac01\U00000308\U0000200d", {44033}, {3}}, {L"\U0000ac01\U00000378", {44033, 888}, {1, 2}}, {L"\U0000ac01\U00000308\U00000378", {44033, 888}, {2, 3}}, - {L"\U00000900\U00000020", {2304, 32}, {1, 2}}, - {L"\U00000900\U00000308\U00000020", {2304, 32}, {2, 3}}, - {L"\U00000900\U0000000d", {2304, 13}, {1, 2}}, - {L"\U00000900\U00000308\U0000000d", {2304, 13}, {2, 3}}, - {L"\U00000900\U0000000a", {2304, 10}, {1, 2}}, - {L"\U00000900\U00000308\U0000000a", {2304, 10}, {2, 3}}, - {L"\U00000900\U00000001", {2304, 1}, {1, 2}}, - {L"\U00000900\U00000308\U00000001", {2304, 1}, {2, 3}}, - {L"\U00000900\U0000034f", {2304}, {2}}, - {L"\U00000900\U00000308\U0000034f", {2304}, {3}}, - {L"\U00000900\U0001f1e6", {2304, 127462}, {1, 3}}, - {L"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {2, 4}}, - {L"\U00000900\U00000600", {2304, 1536}, {1, 2}}, - {L"\U00000900\U00000308\U00000600", {2304, 1536}, {2, 3}}, - {L"\U00000900\U00000a03", {2304}, {2}}, - {L"\U00000900\U00000308\U00000a03", {2304}, {3}}, - {L"\U00000900\U00001100", {2304, 4352}, {1, 2}}, - {L"\U00000900\U00000308\U00001100", {2304, 4352}, {2, 3}}, - {L"\U00000900\U00001160", {2304, 4448}, {1, 2}}, - {L"\U00000900\U00000308\U00001160", {2304, 4448}, {2, 3}}, - {L"\U00000900\U000011a8", {2304, 4520}, {1, 2}}, - {L"\U00000900\U00000308\U000011a8", {2304, 4520}, {2, 3}}, - {L"\U00000900\U0000ac00", {2304, 44032}, {1, 2}}, - {L"\U00000900\U00000308\U0000ac00", {2304, 44032}, {2, 3}}, - {L"\U00000900\U0000ac01", {2304, 44033}, {1, 2}}, - {L"\U00000900\U00000308\U0000ac01", {2304, 44033}, {2, 3}}, - {L"\U00000900\U00000900", {2304}, {2}}, - {L"\U00000900\U00000308\U00000900", {2304}, {3}}, - {L"\U00000900\U00000903", {2304}, {2}}, - {L"\U00000900\U00000308\U00000903", {2304}, {3}}, - {L"\U00000900\U00000904", {2304, 2308}, {1, 2}}, - {L"\U00000900\U00000308\U00000904", {2304, 2308}, {2, 3}}, - {L"\U00000900\U00000d4e", {2304, 3406}, {1, 2}}, - {L"\U00000900\U00000308\U00000d4e", {2304, 3406}, {2, 3}}, - {L"\U00000900\U00000915", {2304, 2325}, {1, 2}}, - {L"\U00000900\U00000308\U00000915", {2304, 2325}, {2, 3}}, - {L"\U00000900\U0000231a", {2304, 8986}, {1, 2}}, - {L"\U00000900\U00000308\U0000231a", {2304, 8986}, {2, 3}}, - {L"\U00000900\U00000300", {2304}, {2}}, - {L"\U00000900\U00000308\U00000300", {2304}, {3}}, - {L"\U00000900\U0000093c", {2304}, {2}}, - {L"\U00000900\U00000308\U0000093c", {2304}, {3}}, - {L"\U00000900\U0000094d", {2304}, {2}}, - {L"\U00000900\U00000308\U0000094d", {2304}, {3}}, - {L"\U00000900\U0000200d", {2304}, {2}}, - {L"\U00000900\U00000308\U0000200d", {2304}, {3}}, - {L"\U00000900\U00000378", {2304, 888}, {1, 2}}, - {L"\U00000900\U00000308\U00000378", {2304, 888}, {2, 3}}, {L"\U00000903\U00000020", {2307, 32}, {1, 2}}, {L"\U00000903\U00000308\U00000020", {2307, 32}, {2, 3}}, {L"\U00000903\U0000000d", {2307, 13}, {1, 2}}, @@ -1958,8 +1790,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000903\U00000308\U0000000a", {2307, 10}, {2, 3}}, {L"\U00000903\U00000001", {2307, 1}, {1, 2}}, {L"\U00000903\U00000308\U00000001", {2307, 1}, {2, 3}}, - {L"\U00000903\U0000034f", {2307}, {2}}, - {L"\U00000903\U00000308\U0000034f", {2307}, {3}}, + {L"\U00000903\U0000200c", {2307}, {2}}, + {L"\U00000903\U00000308\U0000200c", {2307}, {3}}, {L"\U00000903\U0001f1e6", {2307, 127462}, {1, 3}}, {L"\U00000903\U00000308\U0001f1e6", {2307, 127462}, {2, 4}}, {L"\U00000903\U00000600", {2307, 1536}, {1, 2}}, @@ -1976,8 +1808,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000903\U00000308\U0000ac00", {2307, 44032}, {2, 3}}, {L"\U00000903\U0000ac01", {2307, 44033}, {1, 2}}, {L"\U00000903\U00000308\U0000ac01", {2307, 44033}, {2, 3}}, - {L"\U00000903\U00000900", {2307}, {2}}, - {L"\U00000903\U00000308\U00000900", {2307}, {3}}, {L"\U00000903\U00000903", {2307}, {2}}, {L"\U00000903\U00000308\U00000903", {2307}, {3}}, {L"\U00000903\U00000904", {2307, 2308}, {1, 2}}, @@ -1990,8 +1820,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000903\U00000308\U0000231a", {2307, 8986}, {2, 3}}, {L"\U00000903\U00000300", {2307}, {2}}, {L"\U00000903\U00000308\U00000300", {2307}, {3}}, - {L"\U00000903\U0000093c", {2307}, {2}}, - {L"\U00000903\U00000308\U0000093c", {2307}, {3}}, + {L"\U00000903\U00000900", {2307}, {2}}, + {L"\U00000903\U00000308\U00000900", {2307}, {3}}, {L"\U00000903\U0000094d", {2307}, {2}}, {L"\U00000903\U00000308\U0000094d", {2307}, {3}}, {L"\U00000903\U0000200d", {2307}, {2}}, @@ -2006,8 +1836,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000904\U00000308\U0000000a", {2308, 10}, {2, 3}}, {L"\U00000904\U00000001", {2308, 1}, {1, 2}}, {L"\U00000904\U00000308\U00000001", {2308, 1}, {2, 3}}, - {L"\U00000904\U0000034f", {2308}, {2}}, - {L"\U00000904\U00000308\U0000034f", {2308}, {3}}, + {L"\U00000904\U0000200c", {2308}, {2}}, + {L"\U00000904\U00000308\U0000200c", {2308}, {3}}, {L"\U00000904\U0001f1e6", {2308, 127462}, {1, 3}}, {L"\U00000904\U00000308\U0001f1e6", {2308, 127462}, {2, 4}}, {L"\U00000904\U00000600", {2308, 1536}, {1, 2}}, @@ -2024,8 +1854,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000904\U00000308\U0000ac00", {2308, 44032}, {2, 3}}, {L"\U00000904\U0000ac01", {2308, 44033}, {1, 2}}, {L"\U00000904\U00000308\U0000ac01", {2308, 44033}, {2, 3}}, - {L"\U00000904\U00000900", {2308}, {2}}, - {L"\U00000904\U00000308\U00000900", {2308}, {3}}, {L"\U00000904\U00000903", {2308}, {2}}, {L"\U00000904\U00000308\U00000903", {2308}, {3}}, {L"\U00000904\U00000904", {2308, 2308}, {1, 2}}, @@ -2038,8 +1866,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000904\U00000308\U0000231a", {2308, 8986}, {2, 3}}, {L"\U00000904\U00000300", {2308}, {2}}, {L"\U00000904\U00000308\U00000300", {2308}, {3}}, - {L"\U00000904\U0000093c", {2308}, {2}}, - {L"\U00000904\U00000308\U0000093c", {2308}, {3}}, + {L"\U00000904\U00000900", {2308}, {2}}, + {L"\U00000904\U00000308\U00000900", {2308}, {3}}, {L"\U00000904\U0000094d", {2308}, {2}}, {L"\U00000904\U00000308\U0000094d", {2308}, {3}}, {L"\U00000904\U0000200d", {2308}, {2}}, @@ -2054,8 +1882,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000d4e\U00000308\U0000000a", {3406, 10}, {2, 3}}, {L"\U00000d4e\U00000001", {3406, 1}, {1, 2}}, {L"\U00000d4e\U00000308\U00000001", {3406, 1}, {2, 3}}, - {L"\U00000d4e\U0000034f", {3406}, {2}}, - {L"\U00000d4e\U00000308\U0000034f", {3406}, {3}}, + {L"\U00000d4e\U0000200c", {3406}, {2}}, + {L"\U00000d4e\U00000308\U0000200c", {3406}, {3}}, {L"\U00000d4e\U0001f1e6", {3406}, {3}}, {L"\U00000d4e\U00000308\U0001f1e6", {3406, 127462}, {2, 4}}, {L"\U00000d4e\U00000600", {3406}, {2}}, @@ -2072,8 +1900,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000d4e\U00000308\U0000ac00", {3406, 44032}, {2, 3}}, {L"\U00000d4e\U0000ac01", {3406}, {2}}, {L"\U00000d4e\U00000308\U0000ac01", {3406, 44033}, {2, 3}}, - {L"\U00000d4e\U00000900", {3406}, {2}}, - {L"\U00000d4e\U00000308\U00000900", {3406}, {3}}, {L"\U00000d4e\U00000903", {3406}, {2}}, {L"\U00000d4e\U00000308\U00000903", {3406}, {3}}, {L"\U00000d4e\U00000904", {3406}, {2}}, @@ -2086,8 +1912,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000d4e\U00000308\U0000231a", {3406, 8986}, {2, 3}}, {L"\U00000d4e\U00000300", {3406}, {2}}, {L"\U00000d4e\U00000308\U00000300", {3406}, {3}}, - {L"\U00000d4e\U0000093c", {3406}, {2}}, - {L"\U00000d4e\U00000308\U0000093c", {3406}, {3}}, + {L"\U00000d4e\U00000900", {3406}, {2}}, + {L"\U00000d4e\U00000308\U00000900", {3406}, {3}}, {L"\U00000d4e\U0000094d", {3406}, {2}}, {L"\U00000d4e\U00000308\U0000094d", {3406}, {3}}, {L"\U00000d4e\U0000200d", {3406}, {2}}, @@ -2102,8 +1928,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000915\U00000308\U0000000a", {2325, 10}, {2, 3}}, {L"\U00000915\U00000001", {2325, 1}, {1, 2}}, {L"\U00000915\U00000308\U00000001", {2325, 1}, {2, 3}}, - {L"\U00000915\U0000034f", {2325}, {2}}, - {L"\U00000915\U00000308\U0000034f", {2325}, {3}}, + {L"\U00000915\U0000200c", {2325}, {2}}, + {L"\U00000915\U00000308\U0000200c", {2325}, {3}}, {L"\U00000915\U0001f1e6", {2325, 127462}, {1, 3}}, {L"\U00000915\U00000308\U0001f1e6", {2325, 127462}, {2, 4}}, {L"\U00000915\U00000600", {2325, 1536}, {1, 2}}, @@ -2120,8 +1946,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000915\U00000308\U0000ac00", {2325, 44032}, {2, 3}}, {L"\U00000915\U0000ac01", {2325, 44033}, {1, 2}}, {L"\U00000915\U00000308\U0000ac01", {2325, 44033}, {2, 3}}, - {L"\U00000915\U00000900", {2325}, {2}}, - {L"\U00000915\U00000308\U00000900", {2325}, {3}}, {L"\U00000915\U00000903", {2325}, {2}}, {L"\U00000915\U00000308\U00000903", {2325}, {3}}, {L"\U00000915\U00000904", {2325, 2308}, {1, 2}}, @@ -2134,8 +1958,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000915\U00000308\U0000231a", {2325, 8986}, {2, 3}}, {L"\U00000915\U00000300", {2325}, {2}}, {L"\U00000915\U00000308\U00000300", {2325}, {3}}, - {L"\U00000915\U0000093c", {2325}, {2}}, - {L"\U00000915\U00000308\U0000093c", {2325}, {3}}, + {L"\U00000915\U00000900", {2325}, {2}}, + {L"\U00000915\U00000308\U00000900", {2325}, {3}}, {L"\U00000915\U0000094d", {2325}, {2}}, {L"\U00000915\U00000308\U0000094d", {2325}, {3}}, {L"\U00000915\U0000200d", {2325}, {2}}, @@ -2150,8 +1974,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000231a\U00000308\U0000000a", {8986, 10}, {2, 3}}, {L"\U0000231a\U00000001", {8986, 1}, {1, 2}}, {L"\U0000231a\U00000308\U00000001", {8986, 1}, {2, 3}}, - {L"\U0000231a\U0000034f", {8986}, {2}}, - {L"\U0000231a\U00000308\U0000034f", {8986}, {3}}, + {L"\U0000231a\U0000200c", {8986}, {2}}, + {L"\U0000231a\U00000308\U0000200c", {8986}, {3}}, {L"\U0000231a\U0001f1e6", {8986, 127462}, {1, 3}}, {L"\U0000231a\U00000308\U0001f1e6", {8986, 127462}, {2, 4}}, {L"\U0000231a\U00000600", {8986, 1536}, {1, 2}}, @@ -2168,8 +1992,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000231a\U00000308\U0000ac00", {8986, 44032}, {2, 3}}, {L"\U0000231a\U0000ac01", {8986, 44033}, {1, 2}}, {L"\U0000231a\U00000308\U0000ac01", {8986, 44033}, {2, 3}}, - {L"\U0000231a\U00000900", {8986}, {2}}, - {L"\U0000231a\U00000308\U00000900", {8986}, {3}}, {L"\U0000231a\U00000903", {8986}, {2}}, {L"\U0000231a\U00000308\U00000903", {8986}, {3}}, {L"\U0000231a\U00000904", {8986, 2308}, {1, 2}}, @@ -2182,8 +2004,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000231a\U00000308\U0000231a", {8986, 8986}, {2, 3}}, {L"\U0000231a\U00000300", {8986}, {2}}, {L"\U0000231a\U00000308\U00000300", {8986}, {3}}, - {L"\U0000231a\U0000093c", {8986}, {2}}, - {L"\U0000231a\U00000308\U0000093c", {8986}, {3}}, + {L"\U0000231a\U00000900", {8986}, {2}}, + {L"\U0000231a\U00000308\U00000900", {8986}, {3}}, {L"\U0000231a\U0000094d", {8986}, {2}}, {L"\U0000231a\U00000308\U0000094d", {8986}, {3}}, {L"\U0000231a\U0000200d", {8986}, {2}}, @@ -2198,8 +2020,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000300\U00000308\U0000000a", {768, 10}, {2, 3}}, {L"\U00000300\U00000001", {768, 1}, {1, 2}}, {L"\U00000300\U00000308\U00000001", {768, 1}, {2, 3}}, - {L"\U00000300\U0000034f", {768}, {2}}, - {L"\U00000300\U00000308\U0000034f", {768}, {3}}, + {L"\U00000300\U0000200c", {768}, {2}}, + {L"\U00000300\U00000308\U0000200c", {768}, {3}}, {L"\U00000300\U0001f1e6", {768, 127462}, {1, 3}}, {L"\U00000300\U00000308\U0001f1e6", {768, 127462}, {2, 4}}, {L"\U00000300\U00000600", {768, 1536}, {1, 2}}, @@ -2216,8 +2038,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000300\U00000308\U0000ac00", {768, 44032}, {2, 3}}, {L"\U00000300\U0000ac01", {768, 44033}, {1, 2}}, {L"\U00000300\U00000308\U0000ac01", {768, 44033}, {2, 3}}, - {L"\U00000300\U00000900", {768}, {2}}, - {L"\U00000300\U00000308\U00000900", {768}, {3}}, {L"\U00000300\U00000903", {768}, {2}}, {L"\U00000300\U00000308\U00000903", {768}, {3}}, {L"\U00000300\U00000904", {768, 2308}, {1, 2}}, @@ -2230,62 +2050,60 @@ std::array, 1187> data_utf16 = {{ {L"\U00000300\U00000308\U0000231a", {768, 8986}, {2, 3}}, {L"\U00000300\U00000300", {768}, {2}}, {L"\U00000300\U00000308\U00000300", {768}, {3}}, - {L"\U00000300\U0000093c", {768}, {2}}, - {L"\U00000300\U00000308\U0000093c", {768}, {3}}, + {L"\U00000300\U00000900", {768}, {2}}, + {L"\U00000300\U00000308\U00000900", {768}, {3}}, {L"\U00000300\U0000094d", {768}, {2}}, {L"\U00000300\U00000308\U0000094d", {768}, {3}}, {L"\U00000300\U0000200d", {768}, {2}}, {L"\U00000300\U00000308\U0000200d", {768}, {3}}, {L"\U00000300\U00000378", {768, 888}, {1, 2}}, {L"\U00000300\U00000308\U00000378", {768, 888}, {2, 3}}, - {L"\U0000093c\U00000020", {2364, 32}, {1, 2}}, - {L"\U0000093c\U00000308\U00000020", {2364, 32}, {2, 3}}, - {L"\U0000093c\U0000000d", {2364, 13}, {1, 2}}, - {L"\U0000093c\U00000308\U0000000d", {2364, 13}, {2, 3}}, - {L"\U0000093c\U0000000a", {2364, 10}, {1, 2}}, - {L"\U0000093c\U00000308\U0000000a", {2364, 10}, {2, 3}}, - {L"\U0000093c\U00000001", {2364, 1}, {1, 2}}, - {L"\U0000093c\U00000308\U00000001", {2364, 1}, {2, 3}}, - {L"\U0000093c\U0000034f", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000034f", {2364}, {3}}, - {L"\U0000093c\U0001f1e6", {2364, 127462}, {1, 3}}, - {L"\U0000093c\U00000308\U0001f1e6", {2364, 127462}, {2, 4}}, - {L"\U0000093c\U00000600", {2364, 1536}, {1, 2}}, - {L"\U0000093c\U00000308\U00000600", {2364, 1536}, {2, 3}}, - {L"\U0000093c\U00000a03", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000a03", {2364}, {3}}, - {L"\U0000093c\U00001100", {2364, 4352}, {1, 2}}, - {L"\U0000093c\U00000308\U00001100", {2364, 4352}, {2, 3}}, - {L"\U0000093c\U00001160", {2364, 4448}, {1, 2}}, - {L"\U0000093c\U00000308\U00001160", {2364, 4448}, {2, 3}}, - {L"\U0000093c\U000011a8", {2364, 4520}, {1, 2}}, - {L"\U0000093c\U00000308\U000011a8", {2364, 4520}, {2, 3}}, - {L"\U0000093c\U0000ac00", {2364, 44032}, {1, 2}}, - {L"\U0000093c\U00000308\U0000ac00", {2364, 44032}, {2, 3}}, - {L"\U0000093c\U0000ac01", {2364, 44033}, {1, 2}}, - {L"\U0000093c\U00000308\U0000ac01", {2364, 44033}, {2, 3}}, - {L"\U0000093c\U00000900", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000900", {2364}, {3}}, - {L"\U0000093c\U00000903", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000903", {2364}, {3}}, - {L"\U0000093c\U00000904", {2364, 2308}, {1, 2}}, - {L"\U0000093c\U00000308\U00000904", {2364, 2308}, {2, 3}}, - {L"\U0000093c\U00000d4e", {2364, 3406}, {1, 2}}, - {L"\U0000093c\U00000308\U00000d4e", {2364, 3406}, {2, 3}}, - {L"\U0000093c\U00000915", {2364, 2325}, {1, 2}}, - {L"\U0000093c\U00000308\U00000915", {2364, 2325}, {2, 3}}, - {L"\U0000093c\U0000231a", {2364, 8986}, {1, 2}}, - {L"\U0000093c\U00000308\U0000231a", {2364, 8986}, {2, 3}}, - {L"\U0000093c\U00000300", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000300", {2364}, {3}}, - {L"\U0000093c\U0000093c", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000093c", {2364}, {3}}, - {L"\U0000093c\U0000094d", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000094d", {2364}, {3}}, - {L"\U0000093c\U0000200d", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000200d", {2364}, {3}}, - {L"\U0000093c\U00000378", {2364, 888}, {1, 2}}, - {L"\U0000093c\U00000308\U00000378", {2364, 888}, {2, 3}}, + {L"\U00000900\U00000020", {2304, 32}, {1, 2}}, + {L"\U00000900\U00000308\U00000020", {2304, 32}, {2, 3}}, + {L"\U00000900\U0000000d", {2304, 13}, {1, 2}}, + {L"\U00000900\U00000308\U0000000d", {2304, 13}, {2, 3}}, + {L"\U00000900\U0000000a", {2304, 10}, {1, 2}}, + {L"\U00000900\U00000308\U0000000a", {2304, 10}, {2, 3}}, + {L"\U00000900\U00000001", {2304, 1}, {1, 2}}, + {L"\U00000900\U00000308\U00000001", {2304, 1}, {2, 3}}, + {L"\U00000900\U0000200c", {2304}, {2}}, + {L"\U00000900\U00000308\U0000200c", {2304}, {3}}, + {L"\U00000900\U0001f1e6", {2304, 127462}, {1, 3}}, + {L"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {2, 4}}, + {L"\U00000900\U00000600", {2304, 1536}, {1, 2}}, + {L"\U00000900\U00000308\U00000600", {2304, 1536}, {2, 3}}, + {L"\U00000900\U00000a03", {2304}, {2}}, + {L"\U00000900\U00000308\U00000a03", {2304}, {3}}, + {L"\U00000900\U00001100", {2304, 4352}, {1, 2}}, + {L"\U00000900\U00000308\U00001100", {2304, 4352}, {2, 3}}, + {L"\U00000900\U00001160", {2304, 4448}, {1, 2}}, + {L"\U00000900\U00000308\U00001160", {2304, 4448}, {2, 3}}, + {L"\U00000900\U000011a8", {2304, 4520}, {1, 2}}, + {L"\U00000900\U00000308\U000011a8", {2304, 4520}, {2, 3}}, + {L"\U00000900\U0000ac00", {2304, 44032}, {1, 2}}, + {L"\U00000900\U00000308\U0000ac00", {2304, 44032}, {2, 3}}, + {L"\U00000900\U0000ac01", {2304, 44033}, {1, 2}}, + {L"\U00000900\U00000308\U0000ac01", {2304, 44033}, {2, 3}}, + {L"\U00000900\U00000903", {2304}, {2}}, + {L"\U00000900\U00000308\U00000903", {2304}, {3}}, + {L"\U00000900\U00000904", {2304, 2308}, {1, 2}}, + {L"\U00000900\U00000308\U00000904", {2304, 2308}, {2, 3}}, + {L"\U00000900\U00000d4e", {2304, 3406}, {1, 2}}, + {L"\U00000900\U00000308\U00000d4e", {2304, 3406}, {2, 3}}, + {L"\U00000900\U00000915", {2304, 2325}, {1, 2}}, + {L"\U00000900\U00000308\U00000915", {2304, 2325}, {2, 3}}, + {L"\U00000900\U0000231a", {2304, 8986}, {1, 2}}, + {L"\U00000900\U00000308\U0000231a", {2304, 8986}, {2, 3}}, + {L"\U00000900\U00000300", {2304}, {2}}, + {L"\U00000900\U00000308\U00000300", {2304}, {3}}, + {L"\U00000900\U00000900", {2304}, {2}}, + {L"\U00000900\U00000308\U00000900", {2304}, {3}}, + {L"\U00000900\U0000094d", {2304}, {2}}, + {L"\U00000900\U00000308\U0000094d", {2304}, {3}}, + {L"\U00000900\U0000200d", {2304}, {2}}, + {L"\U00000900\U00000308\U0000200d", {2304}, {3}}, + {L"\U00000900\U00000378", {2304, 888}, {1, 2}}, + {L"\U00000900\U00000308\U00000378", {2304, 888}, {2, 3}}, {L"\U0000094d\U00000020", {2381, 32}, {1, 2}}, {L"\U0000094d\U00000308\U00000020", {2381, 32}, {2, 3}}, {L"\U0000094d\U0000000d", {2381, 13}, {1, 2}}, @@ -2294,8 +2112,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000094d\U00000308\U0000000a", {2381, 10}, {2, 3}}, {L"\U0000094d\U00000001", {2381, 1}, {1, 2}}, {L"\U0000094d\U00000308\U00000001", {2381, 1}, {2, 3}}, - {L"\U0000094d\U0000034f", {2381}, {2}}, - {L"\U0000094d\U00000308\U0000034f", {2381}, {3}}, + {L"\U0000094d\U0000200c", {2381}, {2}}, + {L"\U0000094d\U00000308\U0000200c", {2381}, {3}}, {L"\U0000094d\U0001f1e6", {2381, 127462}, {1, 3}}, {L"\U0000094d\U00000308\U0001f1e6", {2381, 127462}, {2, 4}}, {L"\U0000094d\U00000600", {2381, 1536}, {1, 2}}, @@ -2312,8 +2130,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000094d\U00000308\U0000ac00", {2381, 44032}, {2, 3}}, {L"\U0000094d\U0000ac01", {2381, 44033}, {1, 2}}, {L"\U0000094d\U00000308\U0000ac01", {2381, 44033}, {2, 3}}, - {L"\U0000094d\U00000900", {2381}, {2}}, - {L"\U0000094d\U00000308\U00000900", {2381}, {3}}, {L"\U0000094d\U00000903", {2381}, {2}}, {L"\U0000094d\U00000308\U00000903", {2381}, {3}}, {L"\U0000094d\U00000904", {2381, 2308}, {1, 2}}, @@ -2326,8 +2142,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000094d\U00000308\U0000231a", {2381, 8986}, {2, 3}}, {L"\U0000094d\U00000300", {2381}, {2}}, {L"\U0000094d\U00000308\U00000300", {2381}, {3}}, - {L"\U0000094d\U0000093c", {2381}, {2}}, - {L"\U0000094d\U00000308\U0000093c", {2381}, {3}}, + {L"\U0000094d\U00000900", {2381}, {2}}, + {L"\U0000094d\U00000308\U00000900", {2381}, {3}}, {L"\U0000094d\U0000094d", {2381}, {2}}, {L"\U0000094d\U00000308\U0000094d", {2381}, {3}}, {L"\U0000094d\U0000200d", {2381}, {2}}, @@ -2342,8 +2158,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000200d\U00000308\U0000000a", {8205, 10}, {2, 3}}, {L"\U0000200d\U00000001", {8205, 1}, {1, 2}}, {L"\U0000200d\U00000308\U00000001", {8205, 1}, {2, 3}}, - {L"\U0000200d\U0000034f", {8205}, {2}}, - {L"\U0000200d\U00000308\U0000034f", {8205}, {3}}, + {L"\U0000200d\U0000200c", {8205}, {2}}, + {L"\U0000200d\U00000308\U0000200c", {8205}, {3}}, {L"\U0000200d\U0001f1e6", {8205, 127462}, {1, 3}}, {L"\U0000200d\U00000308\U0001f1e6", {8205, 127462}, {2, 4}}, {L"\U0000200d\U00000600", {8205, 1536}, {1, 2}}, @@ -2360,8 +2176,6 @@ std::array, 1187> data_utf16 = {{ {L"\U0000200d\U00000308\U0000ac00", {8205, 44032}, {2, 3}}, {L"\U0000200d\U0000ac01", {8205, 44033}, {1, 2}}, {L"\U0000200d\U00000308\U0000ac01", {8205, 44033}, {2, 3}}, - {L"\U0000200d\U00000900", {8205}, {2}}, - {L"\U0000200d\U00000308\U00000900", {8205}, {3}}, {L"\U0000200d\U00000903", {8205}, {2}}, {L"\U0000200d\U00000308\U00000903", {8205}, {3}}, {L"\U0000200d\U00000904", {8205, 2308}, {1, 2}}, @@ -2374,8 +2188,8 @@ std::array, 1187> data_utf16 = {{ {L"\U0000200d\U00000308\U0000231a", {8205, 8986}, {2, 3}}, {L"\U0000200d\U00000300", {8205}, {2}}, {L"\U0000200d\U00000308\U00000300", {8205}, {3}}, - {L"\U0000200d\U0000093c", {8205}, {2}}, - {L"\U0000200d\U00000308\U0000093c", {8205}, {3}}, + {L"\U0000200d\U00000900", {8205}, {2}}, + {L"\U0000200d\U00000308\U00000900", {8205}, {3}}, {L"\U0000200d\U0000094d", {8205}, {2}}, {L"\U0000200d\U00000308\U0000094d", {8205}, {3}}, {L"\U0000200d\U0000200d", {8205}, {2}}, @@ -2390,8 +2204,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000378\U00000308\U0000000a", {888, 10}, {2, 3}}, {L"\U00000378\U00000001", {888, 1}, {1, 2}}, {L"\U00000378\U00000308\U00000001", {888, 1}, {2, 3}}, - {L"\U00000378\U0000034f", {888}, {2}}, - {L"\U00000378\U00000308\U0000034f", {888}, {3}}, + {L"\U00000378\U0000200c", {888}, {2}}, + {L"\U00000378\U00000308\U0000200c", {888}, {3}}, {L"\U00000378\U0001f1e6", {888, 127462}, {1, 3}}, {L"\U00000378\U00000308\U0001f1e6", {888, 127462}, {2, 4}}, {L"\U00000378\U00000600", {888, 1536}, {1, 2}}, @@ -2408,8 +2222,6 @@ std::array, 1187> data_utf16 = {{ {L"\U00000378\U00000308\U0000ac00", {888, 44032}, {2, 3}}, {L"\U00000378\U0000ac01", {888, 44033}, {1, 2}}, {L"\U00000378\U00000308\U0000ac01", {888, 44033}, {2, 3}}, - {L"\U00000378\U00000900", {888}, {2}}, - {L"\U00000378\U00000308\U00000900", {888}, {3}}, {L"\U00000378\U00000903", {888}, {2}}, {L"\U00000378\U00000308\U00000903", {888}, {3}}, {L"\U00000378\U00000904", {888, 2308}, {1, 2}}, @@ -2422,8 +2234,8 @@ std::array, 1187> data_utf16 = {{ {L"\U00000378\U00000308\U0000231a", {888, 8986}, {2, 3}}, {L"\U00000378\U00000300", {888}, {2}}, {L"\U00000378\U00000308\U00000300", {888}, {3}}, - {L"\U00000378\U0000093c", {888}, {2}}, - {L"\U00000378\U00000308\U0000093c", {888}, {3}}, + {L"\U00000378\U00000900", {888}, {2}}, + {L"\U00000378\U00000308\U00000900", {888}, {3}}, {L"\U00000378\U0000094d", {888}, {2}}, {L"\U00000378\U00000308\U0000094d", {888}, {3}}, {L"\U00000378\U0000200d", {888}, {2}}, @@ -2471,7 +2283,7 @@ std::array, 1187> data_utf16 = {{ /// Note that most of the data for the UTF-16 and UTF-32 are identical. However /// since the size of the code units differ the breaks can contain different /// values. -std::array, 1187> data_utf32 = {{ +std::array, 1093> data_utf32 = {{ {L"\U00000020\U00000020", {32, 32}, {1, 2}}, {L"\U00000020\U00000308\U00000020", {32, 32}, {2, 3}}, {L"\U00000020\U0000000d", {32, 13}, {1, 2}}, @@ -2480,8 +2292,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000020\U00000308\U0000000a", {32, 10}, {2, 3}}, {L"\U00000020\U00000001", {32, 1}, {1, 2}}, {L"\U00000020\U00000308\U00000001", {32, 1}, {2, 3}}, - {L"\U00000020\U0000034f", {32}, {2}}, - {L"\U00000020\U00000308\U0000034f", {32}, {3}}, + {L"\U00000020\U0000200c", {32}, {2}}, + {L"\U00000020\U00000308\U0000200c", {32}, {3}}, {L"\U00000020\U0001f1e6", {32, 127462}, {1, 2}}, {L"\U00000020\U00000308\U0001f1e6", {32, 127462}, {2, 3}}, {L"\U00000020\U00000600", {32, 1536}, {1, 2}}, @@ -2498,8 +2310,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000020\U00000308\U0000ac00", {32, 44032}, {2, 3}}, {L"\U00000020\U0000ac01", {32, 44033}, {1, 2}}, {L"\U00000020\U00000308\U0000ac01", {32, 44033}, {2, 3}}, - {L"\U00000020\U00000900", {32}, {2}}, - {L"\U00000020\U00000308\U00000900", {32}, {3}}, {L"\U00000020\U00000903", {32}, {2}}, {L"\U00000020\U00000308\U00000903", {32}, {3}}, {L"\U00000020\U00000904", {32, 2308}, {1, 2}}, @@ -2512,8 +2322,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000020\U00000308\U0000231a", {32, 8986}, {2, 3}}, {L"\U00000020\U00000300", {32}, {2}}, {L"\U00000020\U00000308\U00000300", {32}, {3}}, - {L"\U00000020\U0000093c", {32}, {2}}, - {L"\U00000020\U00000308\U0000093c", {32}, {3}}, + {L"\U00000020\U00000900", {32}, {2}}, + {L"\U00000020\U00000308\U00000900", {32}, {3}}, {L"\U00000020\U0000094d", {32}, {2}}, {L"\U00000020\U00000308\U0000094d", {32}, {3}}, {L"\U00000020\U0000200d", {32}, {2}}, @@ -2528,8 +2338,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000d\U00000308\U0000000a", {13, 776, 10}, {1, 2, 3}}, {L"\U0000000d\U00000001", {13, 1}, {1, 2}}, {L"\U0000000d\U00000308\U00000001", {13, 776, 1}, {1, 2, 3}}, - {L"\U0000000d\U0000034f", {13, 847}, {1, 2}}, - {L"\U0000000d\U00000308\U0000034f", {13, 776}, {1, 3}}, + {L"\U0000000d\U0000200c", {13, 8204}, {1, 2}}, + {L"\U0000000d\U00000308\U0000200c", {13, 776}, {1, 3}}, {L"\U0000000d\U0001f1e6", {13, 127462}, {1, 2}}, {L"\U0000000d\U00000308\U0001f1e6", {13, 776, 127462}, {1, 2, 3}}, {L"\U0000000d\U00000600", {13, 1536}, {1, 2}}, @@ -2546,8 +2356,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000d\U00000308\U0000ac00", {13, 776, 44032}, {1, 2, 3}}, {L"\U0000000d\U0000ac01", {13, 44033}, {1, 2}}, {L"\U0000000d\U00000308\U0000ac01", {13, 776, 44033}, {1, 2, 3}}, - {L"\U0000000d\U00000900", {13, 2304}, {1, 2}}, - {L"\U0000000d\U00000308\U00000900", {13, 776}, {1, 3}}, {L"\U0000000d\U00000903", {13, 2307}, {1, 2}}, {L"\U0000000d\U00000308\U00000903", {13, 776}, {1, 3}}, {L"\U0000000d\U00000904", {13, 2308}, {1, 2}}, @@ -2560,8 +2368,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000d\U00000308\U0000231a", {13, 776, 8986}, {1, 2, 3}}, {L"\U0000000d\U00000300", {13, 768}, {1, 2}}, {L"\U0000000d\U00000308\U00000300", {13, 776}, {1, 3}}, - {L"\U0000000d\U0000093c", {13, 2364}, {1, 2}}, - {L"\U0000000d\U00000308\U0000093c", {13, 776}, {1, 3}}, + {L"\U0000000d\U00000900", {13, 2304}, {1, 2}}, + {L"\U0000000d\U00000308\U00000900", {13, 776}, {1, 3}}, {L"\U0000000d\U0000094d", {13, 2381}, {1, 2}}, {L"\U0000000d\U00000308\U0000094d", {13, 776}, {1, 3}}, {L"\U0000000d\U0000200d", {13, 8205}, {1, 2}}, @@ -2576,8 +2384,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000a\U00000308\U0000000a", {10, 776, 10}, {1, 2, 3}}, {L"\U0000000a\U00000001", {10, 1}, {1, 2}}, {L"\U0000000a\U00000308\U00000001", {10, 776, 1}, {1, 2, 3}}, - {L"\U0000000a\U0000034f", {10, 847}, {1, 2}}, - {L"\U0000000a\U00000308\U0000034f", {10, 776}, {1, 3}}, + {L"\U0000000a\U0000200c", {10, 8204}, {1, 2}}, + {L"\U0000000a\U00000308\U0000200c", {10, 776}, {1, 3}}, {L"\U0000000a\U0001f1e6", {10, 127462}, {1, 2}}, {L"\U0000000a\U00000308\U0001f1e6", {10, 776, 127462}, {1, 2, 3}}, {L"\U0000000a\U00000600", {10, 1536}, {1, 2}}, @@ -2594,8 +2402,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000a\U00000308\U0000ac00", {10, 776, 44032}, {1, 2, 3}}, {L"\U0000000a\U0000ac01", {10, 44033}, {1, 2}}, {L"\U0000000a\U00000308\U0000ac01", {10, 776, 44033}, {1, 2, 3}}, - {L"\U0000000a\U00000900", {10, 2304}, {1, 2}}, - {L"\U0000000a\U00000308\U00000900", {10, 776}, {1, 3}}, {L"\U0000000a\U00000903", {10, 2307}, {1, 2}}, {L"\U0000000a\U00000308\U00000903", {10, 776}, {1, 3}}, {L"\U0000000a\U00000904", {10, 2308}, {1, 2}}, @@ -2608,8 +2414,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000000a\U00000308\U0000231a", {10, 776, 8986}, {1, 2, 3}}, {L"\U0000000a\U00000300", {10, 768}, {1, 2}}, {L"\U0000000a\U00000308\U00000300", {10, 776}, {1, 3}}, - {L"\U0000000a\U0000093c", {10, 2364}, {1, 2}}, - {L"\U0000000a\U00000308\U0000093c", {10, 776}, {1, 3}}, + {L"\U0000000a\U00000900", {10, 2304}, {1, 2}}, + {L"\U0000000a\U00000308\U00000900", {10, 776}, {1, 3}}, {L"\U0000000a\U0000094d", {10, 2381}, {1, 2}}, {L"\U0000000a\U00000308\U0000094d", {10, 776}, {1, 3}}, {L"\U0000000a\U0000200d", {10, 8205}, {1, 2}}, @@ -2624,8 +2430,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000001\U00000308\U0000000a", {1, 776, 10}, {1, 2, 3}}, {L"\U00000001\U00000001", {1, 1}, {1, 2}}, {L"\U00000001\U00000308\U00000001", {1, 776, 1}, {1, 2, 3}}, - {L"\U00000001\U0000034f", {1, 847}, {1, 2}}, - {L"\U00000001\U00000308\U0000034f", {1, 776}, {1, 3}}, + {L"\U00000001\U0000200c", {1, 8204}, {1, 2}}, + {L"\U00000001\U00000308\U0000200c", {1, 776}, {1, 3}}, {L"\U00000001\U0001f1e6", {1, 127462}, {1, 2}}, {L"\U00000001\U00000308\U0001f1e6", {1, 776, 127462}, {1, 2, 3}}, {L"\U00000001\U00000600", {1, 1536}, {1, 2}}, @@ -2642,8 +2448,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000001\U00000308\U0000ac00", {1, 776, 44032}, {1, 2, 3}}, {L"\U00000001\U0000ac01", {1, 44033}, {1, 2}}, {L"\U00000001\U00000308\U0000ac01", {1, 776, 44033}, {1, 2, 3}}, - {L"\U00000001\U00000900", {1, 2304}, {1, 2}}, - {L"\U00000001\U00000308\U00000900", {1, 776}, {1, 3}}, {L"\U00000001\U00000903", {1, 2307}, {1, 2}}, {L"\U00000001\U00000308\U00000903", {1, 776}, {1, 3}}, {L"\U00000001\U00000904", {1, 2308}, {1, 2}}, @@ -2656,62 +2460,60 @@ std::array, 1187> data_utf32 = {{ {L"\U00000001\U00000308\U0000231a", {1, 776, 8986}, {1, 2, 3}}, {L"\U00000001\U00000300", {1, 768}, {1, 2}}, {L"\U00000001\U00000308\U00000300", {1, 776}, {1, 3}}, - {L"\U00000001\U0000093c", {1, 2364}, {1, 2}}, - {L"\U00000001\U00000308\U0000093c", {1, 776}, {1, 3}}, + {L"\U00000001\U00000900", {1, 2304}, {1, 2}}, + {L"\U00000001\U00000308\U00000900", {1, 776}, {1, 3}}, {L"\U00000001\U0000094d", {1, 2381}, {1, 2}}, {L"\U00000001\U00000308\U0000094d", {1, 776}, {1, 3}}, {L"\U00000001\U0000200d", {1, 8205}, {1, 2}}, {L"\U00000001\U00000308\U0000200d", {1, 776}, {1, 3}}, {L"\U00000001\U00000378", {1, 888}, {1, 2}}, {L"\U00000001\U00000308\U00000378", {1, 776, 888}, {1, 2, 3}}, - {L"\U0000034f\U00000020", {847, 32}, {1, 2}}, - {L"\U0000034f\U00000308\U00000020", {847, 32}, {2, 3}}, - {L"\U0000034f\U0000000d", {847, 13}, {1, 2}}, - {L"\U0000034f\U00000308\U0000000d", {847, 13}, {2, 3}}, - {L"\U0000034f\U0000000a", {847, 10}, {1, 2}}, - {L"\U0000034f\U00000308\U0000000a", {847, 10}, {2, 3}}, - {L"\U0000034f\U00000001", {847, 1}, {1, 2}}, - {L"\U0000034f\U00000308\U00000001", {847, 1}, {2, 3}}, - {L"\U0000034f\U0000034f", {847}, {2}}, - {L"\U0000034f\U00000308\U0000034f", {847}, {3}}, - {L"\U0000034f\U0001f1e6", {847, 127462}, {1, 2}}, - {L"\U0000034f\U00000308\U0001f1e6", {847, 127462}, {2, 3}}, - {L"\U0000034f\U00000600", {847, 1536}, {1, 2}}, - {L"\U0000034f\U00000308\U00000600", {847, 1536}, {2, 3}}, - {L"\U0000034f\U00000a03", {847}, {2}}, - {L"\U0000034f\U00000308\U00000a03", {847}, {3}}, - {L"\U0000034f\U00001100", {847, 4352}, {1, 2}}, - {L"\U0000034f\U00000308\U00001100", {847, 4352}, {2, 3}}, - {L"\U0000034f\U00001160", {847, 4448}, {1, 2}}, - {L"\U0000034f\U00000308\U00001160", {847, 4448}, {2, 3}}, - {L"\U0000034f\U000011a8", {847, 4520}, {1, 2}}, - {L"\U0000034f\U00000308\U000011a8", {847, 4520}, {2, 3}}, - {L"\U0000034f\U0000ac00", {847, 44032}, {1, 2}}, - {L"\U0000034f\U00000308\U0000ac00", {847, 44032}, {2, 3}}, - {L"\U0000034f\U0000ac01", {847, 44033}, {1, 2}}, - {L"\U0000034f\U00000308\U0000ac01", {847, 44033}, {2, 3}}, - {L"\U0000034f\U00000900", {847}, {2}}, - {L"\U0000034f\U00000308\U00000900", {847}, {3}}, - {L"\U0000034f\U00000903", {847}, {2}}, - {L"\U0000034f\U00000308\U00000903", {847}, {3}}, - {L"\U0000034f\U00000904", {847, 2308}, {1, 2}}, - {L"\U0000034f\U00000308\U00000904", {847, 2308}, {2, 3}}, - {L"\U0000034f\U00000d4e", {847, 3406}, {1, 2}}, - {L"\U0000034f\U00000308\U00000d4e", {847, 3406}, {2, 3}}, - {L"\U0000034f\U00000915", {847, 2325}, {1, 2}}, - {L"\U0000034f\U00000308\U00000915", {847, 2325}, {2, 3}}, - {L"\U0000034f\U0000231a", {847, 8986}, {1, 2}}, - {L"\U0000034f\U00000308\U0000231a", {847, 8986}, {2, 3}}, - {L"\U0000034f\U00000300", {847}, {2}}, - {L"\U0000034f\U00000308\U00000300", {847}, {3}}, - {L"\U0000034f\U0000093c", {847}, {2}}, - {L"\U0000034f\U00000308\U0000093c", {847}, {3}}, - {L"\U0000034f\U0000094d", {847}, {2}}, - {L"\U0000034f\U00000308\U0000094d", {847}, {3}}, - {L"\U0000034f\U0000200d", {847}, {2}}, - {L"\U0000034f\U00000308\U0000200d", {847}, {3}}, - {L"\U0000034f\U00000378", {847, 888}, {1, 2}}, - {L"\U0000034f\U00000308\U00000378", {847, 888}, {2, 3}}, + {L"\U0000200c\U00000020", {8204, 32}, {1, 2}}, + {L"\U0000200c\U00000308\U00000020", {8204, 32}, {2, 3}}, + {L"\U0000200c\U0000000d", {8204, 13}, {1, 2}}, + {L"\U0000200c\U00000308\U0000000d", {8204, 13}, {2, 3}}, + {L"\U0000200c\U0000000a", {8204, 10}, {1, 2}}, + {L"\U0000200c\U00000308\U0000000a", {8204, 10}, {2, 3}}, + {L"\U0000200c\U00000001", {8204, 1}, {1, 2}}, + {L"\U0000200c\U00000308\U00000001", {8204, 1}, {2, 3}}, + {L"\U0000200c\U0000200c", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000200c", {8204}, {3}}, + {L"\U0000200c\U0001f1e6", {8204, 127462}, {1, 2}}, + {L"\U0000200c\U00000308\U0001f1e6", {8204, 127462}, {2, 3}}, + {L"\U0000200c\U00000600", {8204, 1536}, {1, 2}}, + {L"\U0000200c\U00000308\U00000600", {8204, 1536}, {2, 3}}, + {L"\U0000200c\U00000a03", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000a03", {8204}, {3}}, + {L"\U0000200c\U00001100", {8204, 4352}, {1, 2}}, + {L"\U0000200c\U00000308\U00001100", {8204, 4352}, {2, 3}}, + {L"\U0000200c\U00001160", {8204, 4448}, {1, 2}}, + {L"\U0000200c\U00000308\U00001160", {8204, 4448}, {2, 3}}, + {L"\U0000200c\U000011a8", {8204, 4520}, {1, 2}}, + {L"\U0000200c\U00000308\U000011a8", {8204, 4520}, {2, 3}}, + {L"\U0000200c\U0000ac00", {8204, 44032}, {1, 2}}, + {L"\U0000200c\U00000308\U0000ac00", {8204, 44032}, {2, 3}}, + {L"\U0000200c\U0000ac01", {8204, 44033}, {1, 2}}, + {L"\U0000200c\U00000308\U0000ac01", {8204, 44033}, {2, 3}}, + {L"\U0000200c\U00000903", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000903", {8204}, {3}}, + {L"\U0000200c\U00000904", {8204, 2308}, {1, 2}}, + {L"\U0000200c\U00000308\U00000904", {8204, 2308}, {2, 3}}, + {L"\U0000200c\U00000d4e", {8204, 3406}, {1, 2}}, + {L"\U0000200c\U00000308\U00000d4e", {8204, 3406}, {2, 3}}, + {L"\U0000200c\U00000915", {8204, 2325}, {1, 2}}, + {L"\U0000200c\U00000308\U00000915", {8204, 2325}, {2, 3}}, + {L"\U0000200c\U0000231a", {8204, 8986}, {1, 2}}, + {L"\U0000200c\U00000308\U0000231a", {8204, 8986}, {2, 3}}, + {L"\U0000200c\U00000300", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000300", {8204}, {3}}, + {L"\U0000200c\U00000900", {8204}, {2}}, + {L"\U0000200c\U00000308\U00000900", {8204}, {3}}, + {L"\U0000200c\U0000094d", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000094d", {8204}, {3}}, + {L"\U0000200c\U0000200d", {8204}, {2}}, + {L"\U0000200c\U00000308\U0000200d", {8204}, {3}}, + {L"\U0000200c\U00000378", {8204, 888}, {1, 2}}, + {L"\U0000200c\U00000308\U00000378", {8204, 888}, {2, 3}}, {L"\U0001f1e6\U00000020", {127462, 32}, {1, 2}}, {L"\U0001f1e6\U00000308\U00000020", {127462, 32}, {2, 3}}, {L"\U0001f1e6\U0000000d", {127462, 13}, {1, 2}}, @@ -2720,8 +2522,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0001f1e6\U00000308\U0000000a", {127462, 10}, {2, 3}}, {L"\U0001f1e6\U00000001", {127462, 1}, {1, 2}}, {L"\U0001f1e6\U00000308\U00000001", {127462, 1}, {2, 3}}, - {L"\U0001f1e6\U0000034f", {127462}, {2}}, - {L"\U0001f1e6\U00000308\U0000034f", {127462}, {3}}, + {L"\U0001f1e6\U0000200c", {127462}, {2}}, + {L"\U0001f1e6\U00000308\U0000200c", {127462}, {3}}, {L"\U0001f1e6\U0001f1e6", {127462}, {2}}, {L"\U0001f1e6\U00000308\U0001f1e6", {127462, 127462}, {2, 3}}, {L"\U0001f1e6\U00000600", {127462, 1536}, {1, 2}}, @@ -2738,8 +2540,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0001f1e6\U00000308\U0000ac00", {127462, 44032}, {2, 3}}, {L"\U0001f1e6\U0000ac01", {127462, 44033}, {1, 2}}, {L"\U0001f1e6\U00000308\U0000ac01", {127462, 44033}, {2, 3}}, - {L"\U0001f1e6\U00000900", {127462}, {2}}, - {L"\U0001f1e6\U00000308\U00000900", {127462}, {3}}, {L"\U0001f1e6\U00000903", {127462}, {2}}, {L"\U0001f1e6\U00000308\U00000903", {127462}, {3}}, {L"\U0001f1e6\U00000904", {127462, 2308}, {1, 2}}, @@ -2752,8 +2552,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0001f1e6\U00000308\U0000231a", {127462, 8986}, {2, 3}}, {L"\U0001f1e6\U00000300", {127462}, {2}}, {L"\U0001f1e6\U00000308\U00000300", {127462}, {3}}, - {L"\U0001f1e6\U0000093c", {127462}, {2}}, - {L"\U0001f1e6\U00000308\U0000093c", {127462}, {3}}, + {L"\U0001f1e6\U00000900", {127462}, {2}}, + {L"\U0001f1e6\U00000308\U00000900", {127462}, {3}}, {L"\U0001f1e6\U0000094d", {127462}, {2}}, {L"\U0001f1e6\U00000308\U0000094d", {127462}, {3}}, {L"\U0001f1e6\U0000200d", {127462}, {2}}, @@ -2768,8 +2568,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000600\U00000308\U0000000a", {1536, 10}, {2, 3}}, {L"\U00000600\U00000001", {1536, 1}, {1, 2}}, {L"\U00000600\U00000308\U00000001", {1536, 1}, {2, 3}}, - {L"\U00000600\U0000034f", {1536}, {2}}, - {L"\U00000600\U00000308\U0000034f", {1536}, {3}}, + {L"\U00000600\U0000200c", {1536}, {2}}, + {L"\U00000600\U00000308\U0000200c", {1536}, {3}}, {L"\U00000600\U0001f1e6", {1536}, {2}}, {L"\U00000600\U00000308\U0001f1e6", {1536, 127462}, {2, 3}}, {L"\U00000600\U00000600", {1536}, {2}}, @@ -2786,8 +2586,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000600\U00000308\U0000ac00", {1536, 44032}, {2, 3}}, {L"\U00000600\U0000ac01", {1536}, {2}}, {L"\U00000600\U00000308\U0000ac01", {1536, 44033}, {2, 3}}, - {L"\U00000600\U00000900", {1536}, {2}}, - {L"\U00000600\U00000308\U00000900", {1536}, {3}}, {L"\U00000600\U00000903", {1536}, {2}}, {L"\U00000600\U00000308\U00000903", {1536}, {3}}, {L"\U00000600\U00000904", {1536}, {2}}, @@ -2800,8 +2598,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000600\U00000308\U0000231a", {1536, 8986}, {2, 3}}, {L"\U00000600\U00000300", {1536}, {2}}, {L"\U00000600\U00000308\U00000300", {1536}, {3}}, - {L"\U00000600\U0000093c", {1536}, {2}}, - {L"\U00000600\U00000308\U0000093c", {1536}, {3}}, + {L"\U00000600\U00000900", {1536}, {2}}, + {L"\U00000600\U00000308\U00000900", {1536}, {3}}, {L"\U00000600\U0000094d", {1536}, {2}}, {L"\U00000600\U00000308\U0000094d", {1536}, {3}}, {L"\U00000600\U0000200d", {1536}, {2}}, @@ -2816,8 +2614,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000a03\U00000308\U0000000a", {2563, 10}, {2, 3}}, {L"\U00000a03\U00000001", {2563, 1}, {1, 2}}, {L"\U00000a03\U00000308\U00000001", {2563, 1}, {2, 3}}, - {L"\U00000a03\U0000034f", {2563}, {2}}, - {L"\U00000a03\U00000308\U0000034f", {2563}, {3}}, + {L"\U00000a03\U0000200c", {2563}, {2}}, + {L"\U00000a03\U00000308\U0000200c", {2563}, {3}}, {L"\U00000a03\U0001f1e6", {2563, 127462}, {1, 2}}, {L"\U00000a03\U00000308\U0001f1e6", {2563, 127462}, {2, 3}}, {L"\U00000a03\U00000600", {2563, 1536}, {1, 2}}, @@ -2834,8 +2632,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000a03\U00000308\U0000ac00", {2563, 44032}, {2, 3}}, {L"\U00000a03\U0000ac01", {2563, 44033}, {1, 2}}, {L"\U00000a03\U00000308\U0000ac01", {2563, 44033}, {2, 3}}, - {L"\U00000a03\U00000900", {2563}, {2}}, - {L"\U00000a03\U00000308\U00000900", {2563}, {3}}, {L"\U00000a03\U00000903", {2563}, {2}}, {L"\U00000a03\U00000308\U00000903", {2563}, {3}}, {L"\U00000a03\U00000904", {2563, 2308}, {1, 2}}, @@ -2848,8 +2644,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000a03\U00000308\U0000231a", {2563, 8986}, {2, 3}}, {L"\U00000a03\U00000300", {2563}, {2}}, {L"\U00000a03\U00000308\U00000300", {2563}, {3}}, - {L"\U00000a03\U0000093c", {2563}, {2}}, - {L"\U00000a03\U00000308\U0000093c", {2563}, {3}}, + {L"\U00000a03\U00000900", {2563}, {2}}, + {L"\U00000a03\U00000308\U00000900", {2563}, {3}}, {L"\U00000a03\U0000094d", {2563}, {2}}, {L"\U00000a03\U00000308\U0000094d", {2563}, {3}}, {L"\U00000a03\U0000200d", {2563}, {2}}, @@ -2864,8 +2660,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00001100\U00000308\U0000000a", {4352, 10}, {2, 3}}, {L"\U00001100\U00000001", {4352, 1}, {1, 2}}, {L"\U00001100\U00000308\U00000001", {4352, 1}, {2, 3}}, - {L"\U00001100\U0000034f", {4352}, {2}}, - {L"\U00001100\U00000308\U0000034f", {4352}, {3}}, + {L"\U00001100\U0000200c", {4352}, {2}}, + {L"\U00001100\U00000308\U0000200c", {4352}, {3}}, {L"\U00001100\U0001f1e6", {4352, 127462}, {1, 2}}, {L"\U00001100\U00000308\U0001f1e6", {4352, 127462}, {2, 3}}, {L"\U00001100\U00000600", {4352, 1536}, {1, 2}}, @@ -2882,8 +2678,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00001100\U00000308\U0000ac00", {4352, 44032}, {2, 3}}, {L"\U00001100\U0000ac01", {4352}, {2}}, {L"\U00001100\U00000308\U0000ac01", {4352, 44033}, {2, 3}}, - {L"\U00001100\U00000900", {4352}, {2}}, - {L"\U00001100\U00000308\U00000900", {4352}, {3}}, {L"\U00001100\U00000903", {4352}, {2}}, {L"\U00001100\U00000308\U00000903", {4352}, {3}}, {L"\U00001100\U00000904", {4352, 2308}, {1, 2}}, @@ -2896,8 +2690,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00001100\U00000308\U0000231a", {4352, 8986}, {2, 3}}, {L"\U00001100\U00000300", {4352}, {2}}, {L"\U00001100\U00000308\U00000300", {4352}, {3}}, - {L"\U00001100\U0000093c", {4352}, {2}}, - {L"\U00001100\U00000308\U0000093c", {4352}, {3}}, + {L"\U00001100\U00000900", {4352}, {2}}, + {L"\U00001100\U00000308\U00000900", {4352}, {3}}, {L"\U00001100\U0000094d", {4352}, {2}}, {L"\U00001100\U00000308\U0000094d", {4352}, {3}}, {L"\U00001100\U0000200d", {4352}, {2}}, @@ -2912,8 +2706,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00001160\U00000308\U0000000a", {4448, 10}, {2, 3}}, {L"\U00001160\U00000001", {4448, 1}, {1, 2}}, {L"\U00001160\U00000308\U00000001", {4448, 1}, {2, 3}}, - {L"\U00001160\U0000034f", {4448}, {2}}, - {L"\U00001160\U00000308\U0000034f", {4448}, {3}}, + {L"\U00001160\U0000200c", {4448}, {2}}, + {L"\U00001160\U00000308\U0000200c", {4448}, {3}}, {L"\U00001160\U0001f1e6", {4448, 127462}, {1, 2}}, {L"\U00001160\U00000308\U0001f1e6", {4448, 127462}, {2, 3}}, {L"\U00001160\U00000600", {4448, 1536}, {1, 2}}, @@ -2930,8 +2724,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00001160\U00000308\U0000ac00", {4448, 44032}, {2, 3}}, {L"\U00001160\U0000ac01", {4448, 44033}, {1, 2}}, {L"\U00001160\U00000308\U0000ac01", {4448, 44033}, {2, 3}}, - {L"\U00001160\U00000900", {4448}, {2}}, - {L"\U00001160\U00000308\U00000900", {4448}, {3}}, {L"\U00001160\U00000903", {4448}, {2}}, {L"\U00001160\U00000308\U00000903", {4448}, {3}}, {L"\U00001160\U00000904", {4448, 2308}, {1, 2}}, @@ -2944,8 +2736,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00001160\U00000308\U0000231a", {4448, 8986}, {2, 3}}, {L"\U00001160\U00000300", {4448}, {2}}, {L"\U00001160\U00000308\U00000300", {4448}, {3}}, - {L"\U00001160\U0000093c", {4448}, {2}}, - {L"\U00001160\U00000308\U0000093c", {4448}, {3}}, + {L"\U00001160\U00000900", {4448}, {2}}, + {L"\U00001160\U00000308\U00000900", {4448}, {3}}, {L"\U00001160\U0000094d", {4448}, {2}}, {L"\U00001160\U00000308\U0000094d", {4448}, {3}}, {L"\U00001160\U0000200d", {4448}, {2}}, @@ -2960,8 +2752,8 @@ std::array, 1187> data_utf32 = {{ {L"\U000011a8\U00000308\U0000000a", {4520, 10}, {2, 3}}, {L"\U000011a8\U00000001", {4520, 1}, {1, 2}}, {L"\U000011a8\U00000308\U00000001", {4520, 1}, {2, 3}}, - {L"\U000011a8\U0000034f", {4520}, {2}}, - {L"\U000011a8\U00000308\U0000034f", {4520}, {3}}, + {L"\U000011a8\U0000200c", {4520}, {2}}, + {L"\U000011a8\U00000308\U0000200c", {4520}, {3}}, {L"\U000011a8\U0001f1e6", {4520, 127462}, {1, 2}}, {L"\U000011a8\U00000308\U0001f1e6", {4520, 127462}, {2, 3}}, {L"\U000011a8\U00000600", {4520, 1536}, {1, 2}}, @@ -2978,8 +2770,6 @@ std::array, 1187> data_utf32 = {{ {L"\U000011a8\U00000308\U0000ac00", {4520, 44032}, {2, 3}}, {L"\U000011a8\U0000ac01", {4520, 44033}, {1, 2}}, {L"\U000011a8\U00000308\U0000ac01", {4520, 44033}, {2, 3}}, - {L"\U000011a8\U00000900", {4520}, {2}}, - {L"\U000011a8\U00000308\U00000900", {4520}, {3}}, {L"\U000011a8\U00000903", {4520}, {2}}, {L"\U000011a8\U00000308\U00000903", {4520}, {3}}, {L"\U000011a8\U00000904", {4520, 2308}, {1, 2}}, @@ -2992,8 +2782,8 @@ std::array, 1187> data_utf32 = {{ {L"\U000011a8\U00000308\U0000231a", {4520, 8986}, {2, 3}}, {L"\U000011a8\U00000300", {4520}, {2}}, {L"\U000011a8\U00000308\U00000300", {4520}, {3}}, - {L"\U000011a8\U0000093c", {4520}, {2}}, - {L"\U000011a8\U00000308\U0000093c", {4520}, {3}}, + {L"\U000011a8\U00000900", {4520}, {2}}, + {L"\U000011a8\U00000308\U00000900", {4520}, {3}}, {L"\U000011a8\U0000094d", {4520}, {2}}, {L"\U000011a8\U00000308\U0000094d", {4520}, {3}}, {L"\U000011a8\U0000200d", {4520}, {2}}, @@ -3008,8 +2798,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac00\U00000308\U0000000a", {44032, 10}, {2, 3}}, {L"\U0000ac00\U00000001", {44032, 1}, {1, 2}}, {L"\U0000ac00\U00000308\U00000001", {44032, 1}, {2, 3}}, - {L"\U0000ac00\U0000034f", {44032}, {2}}, - {L"\U0000ac00\U00000308\U0000034f", {44032}, {3}}, + {L"\U0000ac00\U0000200c", {44032}, {2}}, + {L"\U0000ac00\U00000308\U0000200c", {44032}, {3}}, {L"\U0000ac00\U0001f1e6", {44032, 127462}, {1, 2}}, {L"\U0000ac00\U00000308\U0001f1e6", {44032, 127462}, {2, 3}}, {L"\U0000ac00\U00000600", {44032, 1536}, {1, 2}}, @@ -3026,8 +2816,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac00\U00000308\U0000ac00", {44032, 44032}, {2, 3}}, {L"\U0000ac00\U0000ac01", {44032, 44033}, {1, 2}}, {L"\U0000ac00\U00000308\U0000ac01", {44032, 44033}, {2, 3}}, - {L"\U0000ac00\U00000900", {44032}, {2}}, - {L"\U0000ac00\U00000308\U00000900", {44032}, {3}}, {L"\U0000ac00\U00000903", {44032}, {2}}, {L"\U0000ac00\U00000308\U00000903", {44032}, {3}}, {L"\U0000ac00\U00000904", {44032, 2308}, {1, 2}}, @@ -3040,8 +2828,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac00\U00000308\U0000231a", {44032, 8986}, {2, 3}}, {L"\U0000ac00\U00000300", {44032}, {2}}, {L"\U0000ac00\U00000308\U00000300", {44032}, {3}}, - {L"\U0000ac00\U0000093c", {44032}, {2}}, - {L"\U0000ac00\U00000308\U0000093c", {44032}, {3}}, + {L"\U0000ac00\U00000900", {44032}, {2}}, + {L"\U0000ac00\U00000308\U00000900", {44032}, {3}}, {L"\U0000ac00\U0000094d", {44032}, {2}}, {L"\U0000ac00\U00000308\U0000094d", {44032}, {3}}, {L"\U0000ac00\U0000200d", {44032}, {2}}, @@ -3056,8 +2844,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac01\U00000308\U0000000a", {44033, 10}, {2, 3}}, {L"\U0000ac01\U00000001", {44033, 1}, {1, 2}}, {L"\U0000ac01\U00000308\U00000001", {44033, 1}, {2, 3}}, - {L"\U0000ac01\U0000034f", {44033}, {2}}, - {L"\U0000ac01\U00000308\U0000034f", {44033}, {3}}, + {L"\U0000ac01\U0000200c", {44033}, {2}}, + {L"\U0000ac01\U00000308\U0000200c", {44033}, {3}}, {L"\U0000ac01\U0001f1e6", {44033, 127462}, {1, 2}}, {L"\U0000ac01\U00000308\U0001f1e6", {44033, 127462}, {2, 3}}, {L"\U0000ac01\U00000600", {44033, 1536}, {1, 2}}, @@ -3074,8 +2862,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac01\U00000308\U0000ac00", {44033, 44032}, {2, 3}}, {L"\U0000ac01\U0000ac01", {44033, 44033}, {1, 2}}, {L"\U0000ac01\U00000308\U0000ac01", {44033, 44033}, {2, 3}}, - {L"\U0000ac01\U00000900", {44033}, {2}}, - {L"\U0000ac01\U00000308\U00000900", {44033}, {3}}, {L"\U0000ac01\U00000903", {44033}, {2}}, {L"\U0000ac01\U00000308\U00000903", {44033}, {3}}, {L"\U0000ac01\U00000904", {44033, 2308}, {1, 2}}, @@ -3088,62 +2874,14 @@ std::array, 1187> data_utf32 = {{ {L"\U0000ac01\U00000308\U0000231a", {44033, 8986}, {2, 3}}, {L"\U0000ac01\U00000300", {44033}, {2}}, {L"\U0000ac01\U00000308\U00000300", {44033}, {3}}, - {L"\U0000ac01\U0000093c", {44033}, {2}}, - {L"\U0000ac01\U00000308\U0000093c", {44033}, {3}}, + {L"\U0000ac01\U00000900", {44033}, {2}}, + {L"\U0000ac01\U00000308\U00000900", {44033}, {3}}, {L"\U0000ac01\U0000094d", {44033}, {2}}, {L"\U0000ac01\U00000308\U0000094d", {44033}, {3}}, {L"\U0000ac01\U0000200d", {44033}, {2}}, {L"\U0000ac01\U00000308\U0000200d", {44033}, {3}}, {L"\U0000ac01\U00000378", {44033, 888}, {1, 2}}, {L"\U0000ac01\U00000308\U00000378", {44033, 888}, {2, 3}}, - {L"\U00000900\U00000020", {2304, 32}, {1, 2}}, - {L"\U00000900\U00000308\U00000020", {2304, 32}, {2, 3}}, - {L"\U00000900\U0000000d", {2304, 13}, {1, 2}}, - {L"\U00000900\U00000308\U0000000d", {2304, 13}, {2, 3}}, - {L"\U00000900\U0000000a", {2304, 10}, {1, 2}}, - {L"\U00000900\U00000308\U0000000a", {2304, 10}, {2, 3}}, - {L"\U00000900\U00000001", {2304, 1}, {1, 2}}, - {L"\U00000900\U00000308\U00000001", {2304, 1}, {2, 3}}, - {L"\U00000900\U0000034f", {2304}, {2}}, - {L"\U00000900\U00000308\U0000034f", {2304}, {3}}, - {L"\U00000900\U0001f1e6", {2304, 127462}, {1, 2}}, - {L"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {2, 3}}, - {L"\U00000900\U00000600", {2304, 1536}, {1, 2}}, - {L"\U00000900\U00000308\U00000600", {2304, 1536}, {2, 3}}, - {L"\U00000900\U00000a03", {2304}, {2}}, - {L"\U00000900\U00000308\U00000a03", {2304}, {3}}, - {L"\U00000900\U00001100", {2304, 4352}, {1, 2}}, - {L"\U00000900\U00000308\U00001100", {2304, 4352}, {2, 3}}, - {L"\U00000900\U00001160", {2304, 4448}, {1, 2}}, - {L"\U00000900\U00000308\U00001160", {2304, 4448}, {2, 3}}, - {L"\U00000900\U000011a8", {2304, 4520}, {1, 2}}, - {L"\U00000900\U00000308\U000011a8", {2304, 4520}, {2, 3}}, - {L"\U00000900\U0000ac00", {2304, 44032}, {1, 2}}, - {L"\U00000900\U00000308\U0000ac00", {2304, 44032}, {2, 3}}, - {L"\U00000900\U0000ac01", {2304, 44033}, {1, 2}}, - {L"\U00000900\U00000308\U0000ac01", {2304, 44033}, {2, 3}}, - {L"\U00000900\U00000900", {2304}, {2}}, - {L"\U00000900\U00000308\U00000900", {2304}, {3}}, - {L"\U00000900\U00000903", {2304}, {2}}, - {L"\U00000900\U00000308\U00000903", {2304}, {3}}, - {L"\U00000900\U00000904", {2304, 2308}, {1, 2}}, - {L"\U00000900\U00000308\U00000904", {2304, 2308}, {2, 3}}, - {L"\U00000900\U00000d4e", {2304, 3406}, {1, 2}}, - {L"\U00000900\U00000308\U00000d4e", {2304, 3406}, {2, 3}}, - {L"\U00000900\U00000915", {2304, 2325}, {1, 2}}, - {L"\U00000900\U00000308\U00000915", {2304, 2325}, {2, 3}}, - {L"\U00000900\U0000231a", {2304, 8986}, {1, 2}}, - {L"\U00000900\U00000308\U0000231a", {2304, 8986}, {2, 3}}, - {L"\U00000900\U00000300", {2304}, {2}}, - {L"\U00000900\U00000308\U00000300", {2304}, {3}}, - {L"\U00000900\U0000093c", {2304}, {2}}, - {L"\U00000900\U00000308\U0000093c", {2304}, {3}}, - {L"\U00000900\U0000094d", {2304}, {2}}, - {L"\U00000900\U00000308\U0000094d", {2304}, {3}}, - {L"\U00000900\U0000200d", {2304}, {2}}, - {L"\U00000900\U00000308\U0000200d", {2304}, {3}}, - {L"\U00000900\U00000378", {2304, 888}, {1, 2}}, - {L"\U00000900\U00000308\U00000378", {2304, 888}, {2, 3}}, {L"\U00000903\U00000020", {2307, 32}, {1, 2}}, {L"\U00000903\U00000308\U00000020", {2307, 32}, {2, 3}}, {L"\U00000903\U0000000d", {2307, 13}, {1, 2}}, @@ -3152,8 +2890,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000903\U00000308\U0000000a", {2307, 10}, {2, 3}}, {L"\U00000903\U00000001", {2307, 1}, {1, 2}}, {L"\U00000903\U00000308\U00000001", {2307, 1}, {2, 3}}, - {L"\U00000903\U0000034f", {2307}, {2}}, - {L"\U00000903\U00000308\U0000034f", {2307}, {3}}, + {L"\U00000903\U0000200c", {2307}, {2}}, + {L"\U00000903\U00000308\U0000200c", {2307}, {3}}, {L"\U00000903\U0001f1e6", {2307, 127462}, {1, 2}}, {L"\U00000903\U00000308\U0001f1e6", {2307, 127462}, {2, 3}}, {L"\U00000903\U00000600", {2307, 1536}, {1, 2}}, @@ -3170,8 +2908,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000903\U00000308\U0000ac00", {2307, 44032}, {2, 3}}, {L"\U00000903\U0000ac01", {2307, 44033}, {1, 2}}, {L"\U00000903\U00000308\U0000ac01", {2307, 44033}, {2, 3}}, - {L"\U00000903\U00000900", {2307}, {2}}, - {L"\U00000903\U00000308\U00000900", {2307}, {3}}, {L"\U00000903\U00000903", {2307}, {2}}, {L"\U00000903\U00000308\U00000903", {2307}, {3}}, {L"\U00000903\U00000904", {2307, 2308}, {1, 2}}, @@ -3184,8 +2920,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000903\U00000308\U0000231a", {2307, 8986}, {2, 3}}, {L"\U00000903\U00000300", {2307}, {2}}, {L"\U00000903\U00000308\U00000300", {2307}, {3}}, - {L"\U00000903\U0000093c", {2307}, {2}}, - {L"\U00000903\U00000308\U0000093c", {2307}, {3}}, + {L"\U00000903\U00000900", {2307}, {2}}, + {L"\U00000903\U00000308\U00000900", {2307}, {3}}, {L"\U00000903\U0000094d", {2307}, {2}}, {L"\U00000903\U00000308\U0000094d", {2307}, {3}}, {L"\U00000903\U0000200d", {2307}, {2}}, @@ -3200,8 +2936,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000904\U00000308\U0000000a", {2308, 10}, {2, 3}}, {L"\U00000904\U00000001", {2308, 1}, {1, 2}}, {L"\U00000904\U00000308\U00000001", {2308, 1}, {2, 3}}, - {L"\U00000904\U0000034f", {2308}, {2}}, - {L"\U00000904\U00000308\U0000034f", {2308}, {3}}, + {L"\U00000904\U0000200c", {2308}, {2}}, + {L"\U00000904\U00000308\U0000200c", {2308}, {3}}, {L"\U00000904\U0001f1e6", {2308, 127462}, {1, 2}}, {L"\U00000904\U00000308\U0001f1e6", {2308, 127462}, {2, 3}}, {L"\U00000904\U00000600", {2308, 1536}, {1, 2}}, @@ -3218,8 +2954,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000904\U00000308\U0000ac00", {2308, 44032}, {2, 3}}, {L"\U00000904\U0000ac01", {2308, 44033}, {1, 2}}, {L"\U00000904\U00000308\U0000ac01", {2308, 44033}, {2, 3}}, - {L"\U00000904\U00000900", {2308}, {2}}, - {L"\U00000904\U00000308\U00000900", {2308}, {3}}, {L"\U00000904\U00000903", {2308}, {2}}, {L"\U00000904\U00000308\U00000903", {2308}, {3}}, {L"\U00000904\U00000904", {2308, 2308}, {1, 2}}, @@ -3232,8 +2966,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000904\U00000308\U0000231a", {2308, 8986}, {2, 3}}, {L"\U00000904\U00000300", {2308}, {2}}, {L"\U00000904\U00000308\U00000300", {2308}, {3}}, - {L"\U00000904\U0000093c", {2308}, {2}}, - {L"\U00000904\U00000308\U0000093c", {2308}, {3}}, + {L"\U00000904\U00000900", {2308}, {2}}, + {L"\U00000904\U00000308\U00000900", {2308}, {3}}, {L"\U00000904\U0000094d", {2308}, {2}}, {L"\U00000904\U00000308\U0000094d", {2308}, {3}}, {L"\U00000904\U0000200d", {2308}, {2}}, @@ -3248,8 +2982,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000d4e\U00000308\U0000000a", {3406, 10}, {2, 3}}, {L"\U00000d4e\U00000001", {3406, 1}, {1, 2}}, {L"\U00000d4e\U00000308\U00000001", {3406, 1}, {2, 3}}, - {L"\U00000d4e\U0000034f", {3406}, {2}}, - {L"\U00000d4e\U00000308\U0000034f", {3406}, {3}}, + {L"\U00000d4e\U0000200c", {3406}, {2}}, + {L"\U00000d4e\U00000308\U0000200c", {3406}, {3}}, {L"\U00000d4e\U0001f1e6", {3406}, {2}}, {L"\U00000d4e\U00000308\U0001f1e6", {3406, 127462}, {2, 3}}, {L"\U00000d4e\U00000600", {3406}, {2}}, @@ -3266,8 +3000,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000d4e\U00000308\U0000ac00", {3406, 44032}, {2, 3}}, {L"\U00000d4e\U0000ac01", {3406}, {2}}, {L"\U00000d4e\U00000308\U0000ac01", {3406, 44033}, {2, 3}}, - {L"\U00000d4e\U00000900", {3406}, {2}}, - {L"\U00000d4e\U00000308\U00000900", {3406}, {3}}, {L"\U00000d4e\U00000903", {3406}, {2}}, {L"\U00000d4e\U00000308\U00000903", {3406}, {3}}, {L"\U00000d4e\U00000904", {3406}, {2}}, @@ -3280,8 +3012,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000d4e\U00000308\U0000231a", {3406, 8986}, {2, 3}}, {L"\U00000d4e\U00000300", {3406}, {2}}, {L"\U00000d4e\U00000308\U00000300", {3406}, {3}}, - {L"\U00000d4e\U0000093c", {3406}, {2}}, - {L"\U00000d4e\U00000308\U0000093c", {3406}, {3}}, + {L"\U00000d4e\U00000900", {3406}, {2}}, + {L"\U00000d4e\U00000308\U00000900", {3406}, {3}}, {L"\U00000d4e\U0000094d", {3406}, {2}}, {L"\U00000d4e\U00000308\U0000094d", {3406}, {3}}, {L"\U00000d4e\U0000200d", {3406}, {2}}, @@ -3296,8 +3028,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000915\U00000308\U0000000a", {2325, 10}, {2, 3}}, {L"\U00000915\U00000001", {2325, 1}, {1, 2}}, {L"\U00000915\U00000308\U00000001", {2325, 1}, {2, 3}}, - {L"\U00000915\U0000034f", {2325}, {2}}, - {L"\U00000915\U00000308\U0000034f", {2325}, {3}}, + {L"\U00000915\U0000200c", {2325}, {2}}, + {L"\U00000915\U00000308\U0000200c", {2325}, {3}}, {L"\U00000915\U0001f1e6", {2325, 127462}, {1, 2}}, {L"\U00000915\U00000308\U0001f1e6", {2325, 127462}, {2, 3}}, {L"\U00000915\U00000600", {2325, 1536}, {1, 2}}, @@ -3314,8 +3046,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000915\U00000308\U0000ac00", {2325, 44032}, {2, 3}}, {L"\U00000915\U0000ac01", {2325, 44033}, {1, 2}}, {L"\U00000915\U00000308\U0000ac01", {2325, 44033}, {2, 3}}, - {L"\U00000915\U00000900", {2325}, {2}}, - {L"\U00000915\U00000308\U00000900", {2325}, {3}}, {L"\U00000915\U00000903", {2325}, {2}}, {L"\U00000915\U00000308\U00000903", {2325}, {3}}, {L"\U00000915\U00000904", {2325, 2308}, {1, 2}}, @@ -3328,8 +3058,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000915\U00000308\U0000231a", {2325, 8986}, {2, 3}}, {L"\U00000915\U00000300", {2325}, {2}}, {L"\U00000915\U00000308\U00000300", {2325}, {3}}, - {L"\U00000915\U0000093c", {2325}, {2}}, - {L"\U00000915\U00000308\U0000093c", {2325}, {3}}, + {L"\U00000915\U00000900", {2325}, {2}}, + {L"\U00000915\U00000308\U00000900", {2325}, {3}}, {L"\U00000915\U0000094d", {2325}, {2}}, {L"\U00000915\U00000308\U0000094d", {2325}, {3}}, {L"\U00000915\U0000200d", {2325}, {2}}, @@ -3344,8 +3074,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000231a\U00000308\U0000000a", {8986, 10}, {2, 3}}, {L"\U0000231a\U00000001", {8986, 1}, {1, 2}}, {L"\U0000231a\U00000308\U00000001", {8986, 1}, {2, 3}}, - {L"\U0000231a\U0000034f", {8986}, {2}}, - {L"\U0000231a\U00000308\U0000034f", {8986}, {3}}, + {L"\U0000231a\U0000200c", {8986}, {2}}, + {L"\U0000231a\U00000308\U0000200c", {8986}, {3}}, {L"\U0000231a\U0001f1e6", {8986, 127462}, {1, 2}}, {L"\U0000231a\U00000308\U0001f1e6", {8986, 127462}, {2, 3}}, {L"\U0000231a\U00000600", {8986, 1536}, {1, 2}}, @@ -3362,8 +3092,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000231a\U00000308\U0000ac00", {8986, 44032}, {2, 3}}, {L"\U0000231a\U0000ac01", {8986, 44033}, {1, 2}}, {L"\U0000231a\U00000308\U0000ac01", {8986, 44033}, {2, 3}}, - {L"\U0000231a\U00000900", {8986}, {2}}, - {L"\U0000231a\U00000308\U00000900", {8986}, {3}}, {L"\U0000231a\U00000903", {8986}, {2}}, {L"\U0000231a\U00000308\U00000903", {8986}, {3}}, {L"\U0000231a\U00000904", {8986, 2308}, {1, 2}}, @@ -3376,8 +3104,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000231a\U00000308\U0000231a", {8986, 8986}, {2, 3}}, {L"\U0000231a\U00000300", {8986}, {2}}, {L"\U0000231a\U00000308\U00000300", {8986}, {3}}, - {L"\U0000231a\U0000093c", {8986}, {2}}, - {L"\U0000231a\U00000308\U0000093c", {8986}, {3}}, + {L"\U0000231a\U00000900", {8986}, {2}}, + {L"\U0000231a\U00000308\U00000900", {8986}, {3}}, {L"\U0000231a\U0000094d", {8986}, {2}}, {L"\U0000231a\U00000308\U0000094d", {8986}, {3}}, {L"\U0000231a\U0000200d", {8986}, {2}}, @@ -3392,8 +3120,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000300\U00000308\U0000000a", {768, 10}, {2, 3}}, {L"\U00000300\U00000001", {768, 1}, {1, 2}}, {L"\U00000300\U00000308\U00000001", {768, 1}, {2, 3}}, - {L"\U00000300\U0000034f", {768}, {2}}, - {L"\U00000300\U00000308\U0000034f", {768}, {3}}, + {L"\U00000300\U0000200c", {768}, {2}}, + {L"\U00000300\U00000308\U0000200c", {768}, {3}}, {L"\U00000300\U0001f1e6", {768, 127462}, {1, 2}}, {L"\U00000300\U00000308\U0001f1e6", {768, 127462}, {2, 3}}, {L"\U00000300\U00000600", {768, 1536}, {1, 2}}, @@ -3410,8 +3138,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000300\U00000308\U0000ac00", {768, 44032}, {2, 3}}, {L"\U00000300\U0000ac01", {768, 44033}, {1, 2}}, {L"\U00000300\U00000308\U0000ac01", {768, 44033}, {2, 3}}, - {L"\U00000300\U00000900", {768}, {2}}, - {L"\U00000300\U00000308\U00000900", {768}, {3}}, {L"\U00000300\U00000903", {768}, {2}}, {L"\U00000300\U00000308\U00000903", {768}, {3}}, {L"\U00000300\U00000904", {768, 2308}, {1, 2}}, @@ -3424,62 +3150,60 @@ std::array, 1187> data_utf32 = {{ {L"\U00000300\U00000308\U0000231a", {768, 8986}, {2, 3}}, {L"\U00000300\U00000300", {768}, {2}}, {L"\U00000300\U00000308\U00000300", {768}, {3}}, - {L"\U00000300\U0000093c", {768}, {2}}, - {L"\U00000300\U00000308\U0000093c", {768}, {3}}, + {L"\U00000300\U00000900", {768}, {2}}, + {L"\U00000300\U00000308\U00000900", {768}, {3}}, {L"\U00000300\U0000094d", {768}, {2}}, {L"\U00000300\U00000308\U0000094d", {768}, {3}}, {L"\U00000300\U0000200d", {768}, {2}}, {L"\U00000300\U00000308\U0000200d", {768}, {3}}, {L"\U00000300\U00000378", {768, 888}, {1, 2}}, {L"\U00000300\U00000308\U00000378", {768, 888}, {2, 3}}, - {L"\U0000093c\U00000020", {2364, 32}, {1, 2}}, - {L"\U0000093c\U00000308\U00000020", {2364, 32}, {2, 3}}, - {L"\U0000093c\U0000000d", {2364, 13}, {1, 2}}, - {L"\U0000093c\U00000308\U0000000d", {2364, 13}, {2, 3}}, - {L"\U0000093c\U0000000a", {2364, 10}, {1, 2}}, - {L"\U0000093c\U00000308\U0000000a", {2364, 10}, {2, 3}}, - {L"\U0000093c\U00000001", {2364, 1}, {1, 2}}, - {L"\U0000093c\U00000308\U00000001", {2364, 1}, {2, 3}}, - {L"\U0000093c\U0000034f", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000034f", {2364}, {3}}, - {L"\U0000093c\U0001f1e6", {2364, 127462}, {1, 2}}, - {L"\U0000093c\U00000308\U0001f1e6", {2364, 127462}, {2, 3}}, - {L"\U0000093c\U00000600", {2364, 1536}, {1, 2}}, - {L"\U0000093c\U00000308\U00000600", {2364, 1536}, {2, 3}}, - {L"\U0000093c\U00000a03", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000a03", {2364}, {3}}, - {L"\U0000093c\U00001100", {2364, 4352}, {1, 2}}, - {L"\U0000093c\U00000308\U00001100", {2364, 4352}, {2, 3}}, - {L"\U0000093c\U00001160", {2364, 4448}, {1, 2}}, - {L"\U0000093c\U00000308\U00001160", {2364, 4448}, {2, 3}}, - {L"\U0000093c\U000011a8", {2364, 4520}, {1, 2}}, - {L"\U0000093c\U00000308\U000011a8", {2364, 4520}, {2, 3}}, - {L"\U0000093c\U0000ac00", {2364, 44032}, {1, 2}}, - {L"\U0000093c\U00000308\U0000ac00", {2364, 44032}, {2, 3}}, - {L"\U0000093c\U0000ac01", {2364, 44033}, {1, 2}}, - {L"\U0000093c\U00000308\U0000ac01", {2364, 44033}, {2, 3}}, - {L"\U0000093c\U00000900", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000900", {2364}, {3}}, - {L"\U0000093c\U00000903", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000903", {2364}, {3}}, - {L"\U0000093c\U00000904", {2364, 2308}, {1, 2}}, - {L"\U0000093c\U00000308\U00000904", {2364, 2308}, {2, 3}}, - {L"\U0000093c\U00000d4e", {2364, 3406}, {1, 2}}, - {L"\U0000093c\U00000308\U00000d4e", {2364, 3406}, {2, 3}}, - {L"\U0000093c\U00000915", {2364, 2325}, {1, 2}}, - {L"\U0000093c\U00000308\U00000915", {2364, 2325}, {2, 3}}, - {L"\U0000093c\U0000231a", {2364, 8986}, {1, 2}}, - {L"\U0000093c\U00000308\U0000231a", {2364, 8986}, {2, 3}}, - {L"\U0000093c\U00000300", {2364}, {2}}, - {L"\U0000093c\U00000308\U00000300", {2364}, {3}}, - {L"\U0000093c\U0000093c", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000093c", {2364}, {3}}, - {L"\U0000093c\U0000094d", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000094d", {2364}, {3}}, - {L"\U0000093c\U0000200d", {2364}, {2}}, - {L"\U0000093c\U00000308\U0000200d", {2364}, {3}}, - {L"\U0000093c\U00000378", {2364, 888}, {1, 2}}, - {L"\U0000093c\U00000308\U00000378", {2364, 888}, {2, 3}}, + {L"\U00000900\U00000020", {2304, 32}, {1, 2}}, + {L"\U00000900\U00000308\U00000020", {2304, 32}, {2, 3}}, + {L"\U00000900\U0000000d", {2304, 13}, {1, 2}}, + {L"\U00000900\U00000308\U0000000d", {2304, 13}, {2, 3}}, + {L"\U00000900\U0000000a", {2304, 10}, {1, 2}}, + {L"\U00000900\U00000308\U0000000a", {2304, 10}, {2, 3}}, + {L"\U00000900\U00000001", {2304, 1}, {1, 2}}, + {L"\U00000900\U00000308\U00000001", {2304, 1}, {2, 3}}, + {L"\U00000900\U0000200c", {2304}, {2}}, + {L"\U00000900\U00000308\U0000200c", {2304}, {3}}, + {L"\U00000900\U0001f1e6", {2304, 127462}, {1, 2}}, + {L"\U00000900\U00000308\U0001f1e6", {2304, 127462}, {2, 3}}, + {L"\U00000900\U00000600", {2304, 1536}, {1, 2}}, + {L"\U00000900\U00000308\U00000600", {2304, 1536}, {2, 3}}, + {L"\U00000900\U00000a03", {2304}, {2}}, + {L"\U00000900\U00000308\U00000a03", {2304}, {3}}, + {L"\U00000900\U00001100", {2304, 4352}, {1, 2}}, + {L"\U00000900\U00000308\U00001100", {2304, 4352}, {2, 3}}, + {L"\U00000900\U00001160", {2304, 4448}, {1, 2}}, + {L"\U00000900\U00000308\U00001160", {2304, 4448}, {2, 3}}, + {L"\U00000900\U000011a8", {2304, 4520}, {1, 2}}, + {L"\U00000900\U00000308\U000011a8", {2304, 4520}, {2, 3}}, + {L"\U00000900\U0000ac00", {2304, 44032}, {1, 2}}, + {L"\U00000900\U00000308\U0000ac00", {2304, 44032}, {2, 3}}, + {L"\U00000900\U0000ac01", {2304, 44033}, {1, 2}}, + {L"\U00000900\U00000308\U0000ac01", {2304, 44033}, {2, 3}}, + {L"\U00000900\U00000903", {2304}, {2}}, + {L"\U00000900\U00000308\U00000903", {2304}, {3}}, + {L"\U00000900\U00000904", {2304, 2308}, {1, 2}}, + {L"\U00000900\U00000308\U00000904", {2304, 2308}, {2, 3}}, + {L"\U00000900\U00000d4e", {2304, 3406}, {1, 2}}, + {L"\U00000900\U00000308\U00000d4e", {2304, 3406}, {2, 3}}, + {L"\U00000900\U00000915", {2304, 2325}, {1, 2}}, + {L"\U00000900\U00000308\U00000915", {2304, 2325}, {2, 3}}, + {L"\U00000900\U0000231a", {2304, 8986}, {1, 2}}, + {L"\U00000900\U00000308\U0000231a", {2304, 8986}, {2, 3}}, + {L"\U00000900\U00000300", {2304}, {2}}, + {L"\U00000900\U00000308\U00000300", {2304}, {3}}, + {L"\U00000900\U00000900", {2304}, {2}}, + {L"\U00000900\U00000308\U00000900", {2304}, {3}}, + {L"\U00000900\U0000094d", {2304}, {2}}, + {L"\U00000900\U00000308\U0000094d", {2304}, {3}}, + {L"\U00000900\U0000200d", {2304}, {2}}, + {L"\U00000900\U00000308\U0000200d", {2304}, {3}}, + {L"\U00000900\U00000378", {2304, 888}, {1, 2}}, + {L"\U00000900\U00000308\U00000378", {2304, 888}, {2, 3}}, {L"\U0000094d\U00000020", {2381, 32}, {1, 2}}, {L"\U0000094d\U00000308\U00000020", {2381, 32}, {2, 3}}, {L"\U0000094d\U0000000d", {2381, 13}, {1, 2}}, @@ -3488,8 +3212,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000094d\U00000308\U0000000a", {2381, 10}, {2, 3}}, {L"\U0000094d\U00000001", {2381, 1}, {1, 2}}, {L"\U0000094d\U00000308\U00000001", {2381, 1}, {2, 3}}, - {L"\U0000094d\U0000034f", {2381}, {2}}, - {L"\U0000094d\U00000308\U0000034f", {2381}, {3}}, + {L"\U0000094d\U0000200c", {2381}, {2}}, + {L"\U0000094d\U00000308\U0000200c", {2381}, {3}}, {L"\U0000094d\U0001f1e6", {2381, 127462}, {1, 2}}, {L"\U0000094d\U00000308\U0001f1e6", {2381, 127462}, {2, 3}}, {L"\U0000094d\U00000600", {2381, 1536}, {1, 2}}, @@ -3506,8 +3230,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000094d\U00000308\U0000ac00", {2381, 44032}, {2, 3}}, {L"\U0000094d\U0000ac01", {2381, 44033}, {1, 2}}, {L"\U0000094d\U00000308\U0000ac01", {2381, 44033}, {2, 3}}, - {L"\U0000094d\U00000900", {2381}, {2}}, - {L"\U0000094d\U00000308\U00000900", {2381}, {3}}, {L"\U0000094d\U00000903", {2381}, {2}}, {L"\U0000094d\U00000308\U00000903", {2381}, {3}}, {L"\U0000094d\U00000904", {2381, 2308}, {1, 2}}, @@ -3520,8 +3242,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000094d\U00000308\U0000231a", {2381, 8986}, {2, 3}}, {L"\U0000094d\U00000300", {2381}, {2}}, {L"\U0000094d\U00000308\U00000300", {2381}, {3}}, - {L"\U0000094d\U0000093c", {2381}, {2}}, - {L"\U0000094d\U00000308\U0000093c", {2381}, {3}}, + {L"\U0000094d\U00000900", {2381}, {2}}, + {L"\U0000094d\U00000308\U00000900", {2381}, {3}}, {L"\U0000094d\U0000094d", {2381}, {2}}, {L"\U0000094d\U00000308\U0000094d", {2381}, {3}}, {L"\U0000094d\U0000200d", {2381}, {2}}, @@ -3536,8 +3258,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000200d\U00000308\U0000000a", {8205, 10}, {2, 3}}, {L"\U0000200d\U00000001", {8205, 1}, {1, 2}}, {L"\U0000200d\U00000308\U00000001", {8205, 1}, {2, 3}}, - {L"\U0000200d\U0000034f", {8205}, {2}}, - {L"\U0000200d\U00000308\U0000034f", {8205}, {3}}, + {L"\U0000200d\U0000200c", {8205}, {2}}, + {L"\U0000200d\U00000308\U0000200c", {8205}, {3}}, {L"\U0000200d\U0001f1e6", {8205, 127462}, {1, 2}}, {L"\U0000200d\U00000308\U0001f1e6", {8205, 127462}, {2, 3}}, {L"\U0000200d\U00000600", {8205, 1536}, {1, 2}}, @@ -3554,8 +3276,6 @@ std::array, 1187> data_utf32 = {{ {L"\U0000200d\U00000308\U0000ac00", {8205, 44032}, {2, 3}}, {L"\U0000200d\U0000ac01", {8205, 44033}, {1, 2}}, {L"\U0000200d\U00000308\U0000ac01", {8205, 44033}, {2, 3}}, - {L"\U0000200d\U00000900", {8205}, {2}}, - {L"\U0000200d\U00000308\U00000900", {8205}, {3}}, {L"\U0000200d\U00000903", {8205}, {2}}, {L"\U0000200d\U00000308\U00000903", {8205}, {3}}, {L"\U0000200d\U00000904", {8205, 2308}, {1, 2}}, @@ -3568,8 +3288,8 @@ std::array, 1187> data_utf32 = {{ {L"\U0000200d\U00000308\U0000231a", {8205, 8986}, {2, 3}}, {L"\U0000200d\U00000300", {8205}, {2}}, {L"\U0000200d\U00000308\U00000300", {8205}, {3}}, - {L"\U0000200d\U0000093c", {8205}, {2}}, - {L"\U0000200d\U00000308\U0000093c", {8205}, {3}}, + {L"\U0000200d\U00000900", {8205}, {2}}, + {L"\U0000200d\U00000308\U00000900", {8205}, {3}}, {L"\U0000200d\U0000094d", {8205}, {2}}, {L"\U0000200d\U00000308\U0000094d", {8205}, {3}}, {L"\U0000200d\U0000200d", {8205}, {2}}, @@ -3584,8 +3304,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000378\U00000308\U0000000a", {888, 10}, {2, 3}}, {L"\U00000378\U00000001", {888, 1}, {1, 2}}, {L"\U00000378\U00000308\U00000001", {888, 1}, {2, 3}}, - {L"\U00000378\U0000034f", {888}, {2}}, - {L"\U00000378\U00000308\U0000034f", {888}, {3}}, + {L"\U00000378\U0000200c", {888}, {2}}, + {L"\U00000378\U00000308\U0000200c", {888}, {3}}, {L"\U00000378\U0001f1e6", {888, 127462}, {1, 2}}, {L"\U00000378\U00000308\U0001f1e6", {888, 127462}, {2, 3}}, {L"\U00000378\U00000600", {888, 1536}, {1, 2}}, @@ -3602,8 +3322,6 @@ std::array, 1187> data_utf32 = {{ {L"\U00000378\U00000308\U0000ac00", {888, 44032}, {2, 3}}, {L"\U00000378\U0000ac01", {888, 44033}, {1, 2}}, {L"\U00000378\U00000308\U0000ac01", {888, 44033}, {2, 3}}, - {L"\U00000378\U00000900", {888}, {2}}, - {L"\U00000378\U00000308\U00000900", {888}, {3}}, {L"\U00000378\U00000903", {888}, {2}}, {L"\U00000378\U00000308\U00000903", {888}, {3}}, {L"\U00000378\U00000904", {888, 2308}, {1, 2}}, @@ -3616,8 +3334,8 @@ std::array, 1187> data_utf32 = {{ {L"\U00000378\U00000308\U0000231a", {888, 8986}, {2, 3}}, {L"\U00000378\U00000300", {888}, {2}}, {L"\U00000378\U00000308\U00000300", {888}, {3}}, - {L"\U00000378\U0000093c", {888}, {2}}, - {L"\U00000378\U00000308\U0000093c", {888}, {3}}, + {L"\U00000378\U00000900", {888}, {2}}, + {L"\U00000378\U00000308\U00000900", {888}, {3}}, {L"\U00000378\U0000094d", {888}, {2}}, {L"\U00000378\U00000308\U0000094d", {888}, {3}}, {L"\U00000378\U0000200d", {888}, {2}}, diff --git a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.pass.cpp b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.pass.cpp index dd1f4b607ddfc0..90f7cb2c6ee090 100644 --- a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.pass.cpp +++ b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/extended_grapheme_cluster.pass.cpp @@ -40,15 +40,15 @@ constexpr int count_entries(cluster::__property property) { }); } -static_assert(count_entries(cluster::__property::__Prepend) == 27); +static_assert(count_entries(cluster::__property::__Prepend) == 28); static_assert(count_entries(cluster::__property::__CR) == 1); static_assert(count_entries(cluster::__property::__LF) == 1); static_assert(count_entries(cluster::__property::__Control) == 3893); -static_assert(count_entries(cluster::__property::__Extend) == 2130); +static_assert(count_entries(cluster::__property::__Extend) == 2198); static_assert(count_entries(cluster::__property::__Regional_Indicator) == 26); -static_assert(count_entries(cluster::__property::__SpacingMark) == 395); +static_assert(count_entries(cluster::__property::__SpacingMark) == 378); static_assert(count_entries(cluster::__property::__L) == 125); -static_assert(count_entries(cluster::__property::__V) == 95); +static_assert(count_entries(cluster::__property::__V) == 100); static_assert(count_entries(cluster::__property::__T) == 137); static_assert(count_entries(cluster::__property::__LV) == 399); static_assert(count_entries(cluster::__property::__LVT) == 10773); @@ -68,7 +68,7 @@ constexpr int count_entries(inCB::__property property) { static_assert(count_entries(inCB::__property::__Linker) == 6); static_assert(count_entries(inCB::__property::__Consonant) == 240); -static_assert(count_entries(inCB::__property::__Extend) == 884); +static_assert(count_entries(inCB::__property::__Extend) == 2192); } // namespace diff --git a/libcxx/utils/data/unicode/DerivedCoreProperties.txt b/libcxx/utils/data/unicode/DerivedCoreProperties.txt index 220c55685d4b0b..1075638f1a654e 100644 --- a/libcxx/utils/data/unicode/DerivedCoreProperties.txt +++ b/libcxx/utils/data/unicode/DerivedCoreProperties.txt @@ -1,8 +1,8 @@ -# DerivedCoreProperties-15.1.0.txt -# Date: 2023-08-07, 15:21:24 GMT -# © 2023 Unicode®, Inc. +# DerivedCoreProperties-16.0.0.txt +# Date: 2024-05-31, 18:09:32 GMT +# © 2024 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database # For documentation, see https://www.unicode.org/reports/tr44/ @@ -177,6 +177,7 @@ FF5C ; Math # Sm FULLWIDTH VERTICAL LINE FF5E ; Math # Sm FULLWIDTH TILDE FFE2 ; Math # Sm FULLWIDTH NOT SIGN FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW +10D8E..10D8F ; Math # Sm [2] GARAY PLUS SIGN..GARAY MINUS SIGN 1D400..1D454 ; Math # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G 1D456..1D49C ; Math # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A 1D49E..1D49F ; Math # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D @@ -253,7 +254,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 1EEAB..1EEBB ; Math # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 1EEF0..1EEF1 ; Math # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL -# Total code points: 2310 +# Total code points: 2312 # ================================================ @@ -280,6 +281,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 02EC ; Alphabetic # Lm MODIFIER LETTER VOICING 02EE ; Alphabetic # Lm MODIFIER LETTER DOUBLE APOSTROPHE 0345 ; Alphabetic # Mn COMBINING GREEK YPOGEGRAMMENI +0363..036F ; Alphabetic # Mn [13] COMBINING LATIN SMALL LETTER A..COMBINING LATIN SMALL LETTER X 0370..0373 ; Alphabetic # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI 0374 ; Alphabetic # Lm GREEK NUMERAL SIGN 0376..0377 ; Alphabetic # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA @@ -343,6 +345,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 0860..086A ; Alphabetic # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 0870..0887 ; Alphabetic # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT 0889..088E ; Alphabetic # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL +0897 ; Alphabetic # Mn ARABIC PEPET 08A0..08C8 ; Alphabetic # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; Alphabetic # Lm ARABIC SMALL FARSI YEH 08D4..08DF ; Alphabetic # Mn [12] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH WORD WAQFA @@ -710,7 +713,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 1C4D..1C4F ; Alphabetic # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA 1C5A..1C77 ; Alphabetic # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; Alphabetic # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD -1C80..1C88 ; Alphabetic # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; Alphabetic # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; Alphabetic # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Alphabetic # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CE9..1CEC ; Alphabetic # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL @@ -723,7 +726,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 1D78 ; Alphabetic # Lm MODIFIER LETTER CYRILLIC EN 1D79..1D9A ; Alphabetic # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK 1D9B..1DBF ; Alphabetic # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA -1DE7..1DF4 ; Alphabetic # Mn [14] COMBINING LATIN SMALL LETTER ALPHA..COMBINING LATIN SMALL LETTER U WITH DIAERESIS +1DD3..1DF4 ; Alphabetic # Mn [34] COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE..COMBINING LATIN SMALL LETTER U WITH DIAERESIS 1E00..1F15 ; Alphabetic # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA 1F18..1F1D ; Alphabetic # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA 1F20..1F45 ; Alphabetic # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA @@ -830,10 +833,10 @@ A771..A787 ; Alphabetic # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER A788 ; Alphabetic # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; Alphabetic # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; Alphabetic # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; Alphabetic # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; Alphabetic # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; Alphabetic # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; Alphabetic # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; Alphabetic # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; Alphabetic # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; Alphabetic # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; Alphabetic # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; Alphabetic # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -998,6 +1001,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 105A3..105B1 ; Alphabetic # L& [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; Alphabetic # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; Alphabetic # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; Alphabetic # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; Alphabetic # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; Alphabetic # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; Alphabetic # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -1038,9 +1042,18 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 10CC0..10CF2 ; Alphabetic # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US 10D00..10D23 ; Alphabetic # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA 10D24..10D27 ; Alphabetic # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D4A..10D4D ; Alphabetic # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; Alphabetic # Lm GARAY VOWEL LENGTH MARK +10D4F ; Alphabetic # Lo GARAY SUKUN +10D50..10D65 ; Alphabetic # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D69 ; Alphabetic # Mn GARAY VOWEL SIGN E +10D6F ; Alphabetic # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; Alphabetic # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 10E80..10EA9 ; Alphabetic # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EAB..10EAC ; Alphabetic # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK 10EB0..10EB1 ; Alphabetic # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10EC2..10EC4 ; Alphabetic # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW +10EFC ; Alphabetic # Mn ARABIC COMBINING ALEF OVERLAY 10F00..10F1C ; Alphabetic # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; Alphabetic # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; Alphabetic # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -1121,6 +1134,19 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 11357 ; Alphabetic # Mc GRANTHA AU LENGTH MARK 1135D..11361 ; Alphabetic # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL 11362..11363 ; Alphabetic # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +11380..11389 ; Alphabetic # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; Alphabetic # Lo TULU-TIGALARI LETTER EE +1138E ; Alphabetic # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; Alphabetic # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; Alphabetic # Lo TULU-TIGALARI SIGN AVAGRAHA +113B8..113BA ; Alphabetic # Mc [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II +113BB..113C0 ; Alphabetic # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113C2 ; Alphabetic # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; Alphabetic # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113CA ; Alphabetic # Mc [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; Alphabetic # Mc [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA +113D1 ; Alphabetic # Lo TULU-TIGALARI REPHA +113D3 ; Alphabetic # Lo TULU-TIGALARI SIGN PLUTA 11400..11434 ; Alphabetic # Lo [53] NEWA LETTER A..NEWA LETTER HA 11435..11437 ; Alphabetic # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11438..1143F ; Alphabetic # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI @@ -1163,7 +1189,9 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 116B0..116B5 ; Alphabetic # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU 116B8 ; Alphabetic # Lo TAKRI LETTER ARCHAIC KHA 11700..1171A ; Alphabetic # Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA -1171D..1171F ; Alphabetic # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; Alphabetic # Mn AHOM CONSONANT SIGN MEDIAL LA +1171E ; Alphabetic # Mc AHOM CONSONANT SIGN MEDIAL RA +1171F ; Alphabetic # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11720..11721 ; Alphabetic # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11722..11725 ; Alphabetic # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11726 ; Alphabetic # Mc AHOM VOWEL SIGN E @@ -1211,6 +1239,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 11A97 ; Alphabetic # Mc SOYOMBO SIGN VISARGA 11A9D ; Alphabetic # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; Alphabetic # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; Alphabetic # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO 11C00..11C08 ; Alphabetic # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; Alphabetic # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C2F ; Alphabetic # Mc BHAIKSUKI VOWEL SIGN AA @@ -1264,7 +1293,12 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 12F90..12FF0 ; Alphabetic # Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 13000..1342F ; Alphabetic # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D 13441..13446 ; Alphabetic # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN +13460..143FA ; Alphabetic # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; Alphabetic # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; Alphabetic # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA +1611E..16129 ; Alphabetic # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612A..1612C ; Alphabetic # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA +1612D..1612E ; Alphabetic # Mn [2] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA CONSONANT SIGN MEDIAL RA 16800..16A38 ; Alphabetic # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; Alphabetic # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A70..16ABE ; Alphabetic # Lo [79] TANGSA LETTER OZ..TANGSA LETTER ZA @@ -1273,6 +1307,9 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 16B40..16B43 ; Alphabetic # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM 16B63..16B77 ; Alphabetic # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; Alphabetic # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; Alphabetic # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; Alphabetic # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; Alphabetic # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16E40..16E7F ; Alphabetic # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16F00..16F4A ; Alphabetic # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F4F ; Alphabetic # Mn MIAO SIGN CONSONANT MODIFIER BAR @@ -1285,7 +1322,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 16FF0..16FF1 ; Alphabetic # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY 17000..187F7 ; Alphabetic # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; Alphabetic # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; Alphabetic # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; Alphabetic # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; Alphabetic # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; Alphabetic # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; Alphabetic # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -1348,6 +1385,8 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 1E2C0..1E2EB ; Alphabetic # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH 1E4D0..1E4EA ; Alphabetic # Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL 1E4EB ; Alphabetic # Lm NAG MUNDARI SIGN OJOD +1E5D0..1E5ED ; Alphabetic # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5F0 ; Alphabetic # Lo OL ONAL SIGN HODDOND 1E7E0..1E7E6 ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; Alphabetic # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; Alphabetic # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -1402,7 +1441,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 30000..3134A ; Alphabetic # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A 31350..323AF ; Alphabetic # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF -# Total code points: 138387 +# Total code points: 142759 # ================================================ @@ -1691,6 +1730,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 10FD..10FF ; Lowercase # L& [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN 13F8..13FD ; Lowercase # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV 1C80..1C88 ; Lowercase # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C8A ; Lowercase # L& CYRILLIC SMALL LETTER TJE 1D00..1D2B ; Lowercase # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL 1D2C..1D6A ; Lowercase # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI 1D6B..1D77 ; Lowercase # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G @@ -2032,11 +2072,13 @@ A7C1 ; Lowercase # L& LATIN SMALL LETTER OLD POLISH O A7C3 ; Lowercase # L& LATIN SMALL LETTER ANGLICANA W A7C8 ; Lowercase # L& LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY A7CA ; Lowercase # L& LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7CD ; Lowercase # L& LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D1 ; Lowercase # L& LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; Lowercase # L& LATIN SMALL LETTER DOUBLE THORN A7D5 ; Lowercase # L& LATIN SMALL LETTER DOUBLE WYNN A7D7 ; Lowercase # L& LATIN SMALL LETTER MIDDLE SCOTS S A7D9 ; Lowercase # L& LATIN SMALL LETTER SIGMOID S +A7DB ; Lowercase # L& LATIN SMALL LETTER LAMBDA A7F2..A7F4 ; Lowercase # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F6 ; Lowercase # L& LATIN SMALL LETTER REVERSED HALF H A7F8..A7F9 ; Lowercase # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -2060,6 +2102,7 @@ FF41..FF5A ; Lowercase # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 10787..107B0 ; Lowercase # Lm [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK 107B2..107BA ; Lowercase # Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL 10CC0..10CF2 ; Lowercase # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D70..10D85 ; Lowercase # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118C0..118DF ; Lowercase # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E60..16E7F ; Lowercase # L& [32] MEDEFAIDRIN SMALL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1D41A..1D433 ; Lowercase # L& [26] MATHEMATICAL BOLD SMALL A..MATHEMATICAL BOLD SMALL Z @@ -2096,7 +2139,7 @@ FF41..FF5A ; Lowercase # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 1E030..1E06D ; Lowercase # Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE 1E922..1E943 ; Lowercase # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 2544 +# Total code points: 2569 # ================================================ @@ -2379,6 +2422,7 @@ FF41..FF5A ; Lowercase # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 10C7 ; Uppercase # L& GEORGIAN CAPITAL LETTER YN 10CD ; Uppercase # L& GEORGIAN CAPITAL LETTER AEN 13A0..13F5 ; Uppercase # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV +1C89 ; Uppercase # L& CYRILLIC CAPITAL LETTER TJE 1C90..1CBA ; Uppercase # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Uppercase # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1E00 ; Uppercase # L& LATIN CAPITAL LETTER A WITH RING BELOW @@ -2705,9 +2749,12 @@ A7C0 ; Uppercase # L& LATIN CAPITAL LETTER OLD POLISH O A7C2 ; Uppercase # L& LATIN CAPITAL LETTER ANGLICANA W A7C4..A7C7 ; Uppercase # L& [4] LATIN CAPITAL LETTER C WITH PALATAL HOOK..LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9 ; Uppercase # L& LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY +A7CB..A7CC ; Uppercase # L& [2] LATIN CAPITAL LETTER RAMS HORN..LATIN CAPITAL LETTER S WITH DIAGONAL STROKE A7D0 ; Uppercase # L& LATIN CAPITAL LETTER CLOSED INSULAR G A7D6 ; Uppercase # L& LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8 ; Uppercase # L& LATIN CAPITAL LETTER SIGMOID S +A7DA ; Uppercase # L& LATIN CAPITAL LETTER LAMBDA +A7DC ; Uppercase # L& LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F5 ; Uppercase # L& LATIN CAPITAL LETTER REVERSED HALF H FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z 10400..10427 ; Uppercase # L& [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW @@ -2717,6 +2764,7 @@ FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH 1058C..10592 ; Uppercase # L& [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE 10594..10595 ; Uppercase # L& [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE 10C80..10CB2 ; Uppercase # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10D50..10D65 ; Uppercase # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA 118A0..118BF ; Uppercase # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 16E40..16E5F ; Uppercase # L& [32] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN CAPITAL LETTER Y 1D400..1D419 ; Uppercase # L& [26] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL BOLD CAPITAL Z @@ -2755,7 +2803,7 @@ FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH 1F150..1F169 ; Uppercase # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F170..1F189 ; Uppercase # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 1951 +# Total code points: 1978 # ================================================ @@ -2800,7 +2848,7 @@ FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH 10FD..10FF ; Cased # L& [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN 13A0..13F5 ; Cased # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV 13F8..13FD ; Cased # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV -1C80..1C88 ; Cased # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; Cased # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; Cased # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Cased # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1D00..1D2B ; Cased # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL @@ -2863,10 +2911,10 @@ A722..A76F ; Cased # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN A770 ; Cased # Lm MODIFIER LETTER US A771..A787 ; Cased # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T A78B..A78E ; Cased # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT -A790..A7CA ; Cased # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; Cased # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; Cased # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; Cased # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; Cased # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; Cased # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; Cased # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; Cased # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F8..A7F9 ; Cased # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -2897,6 +2945,8 @@ FF41..FF5A ; Cased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 107B2..107BA ; Cased # Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL 10C80..10CB2 ; Cased # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US 10CC0..10CF2 ; Cased # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D50..10D65 ; Cased # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D70..10D85 ; Cased # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118A0..118DF ; Cased # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E40..16E7F ; Cased # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1D400..1D454 ; Cased # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G @@ -2938,7 +2988,7 @@ FF41..FF5A ; Cased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 1F150..1F169 ; Cased # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F170..1F189 ; Cased # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 4526 +# Total code points: 4578 # ================================================ @@ -3015,7 +3065,7 @@ FF41..FF5A ; Cased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 0859..085B ; Case_Ignorable # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK 0888 ; Case_Ignorable # Sk ARABIC RAISED ROUND DOT 0890..0891 ; Case_Ignorable # Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE -0898..089F ; Case_Ignorable # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; Case_Ignorable # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08C9 ; Case_Ignorable # Lm ARABIC SMALL FARSI YEH 08CA..08E1 ; Case_Ignorable # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA 08E2 ; Case_Ignorable # Cf ARABIC DISPUTED END OF AYAH @@ -3296,8 +3346,11 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 10A3F ; Case_Ignorable # Mn KHAROSHTHI VIRAMA 10AE5..10AE6 ; Case_Ignorable # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW 10D24..10D27 ; Case_Ignorable # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D4E ; Case_Ignorable # Lm GARAY VOWEL LENGTH MARK +10D69..10D6D ; Case_Ignorable # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK +10D6F ; Case_Ignorable # Lm GARAY REDUPLICATION MARK 10EAB..10EAC ; Case_Ignorable # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK -10EFD..10EFF ; Case_Ignorable # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EFC..10EFF ; Case_Ignorable # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F46..10F50 ; Case_Ignorable # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW 10F82..10F85 ; Case_Ignorable # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW 11001 ; Case_Ignorable # Mn BRAHMI SIGN ANUSVARA @@ -3330,6 +3383,11 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 11340 ; Case_Ignorable # Mn GRANTHA VOWEL SIGN II 11366..1136C ; Case_Ignorable # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; Case_Ignorable # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +113BB..113C0 ; Case_Ignorable # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113CE ; Case_Ignorable # Mn TULU-TIGALARI SIGN VIRAMA +113D0 ; Case_Ignorable # Mn TULU-TIGALARI CONJOINER +113D2 ; Case_Ignorable # Mn TULU-TIGALARI GEMINATION MARK +113E1..113E2 ; Case_Ignorable # Mn [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11438..1143F ; Case_Ignorable # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI 11442..11444 ; Case_Ignorable # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA 11446 ; Case_Ignorable # Mn NEWA SIGN NUKTA @@ -3349,7 +3407,8 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 116AD ; Case_Ignorable # Mn TAKRI VOWEL SIGN AA 116B0..116B5 ; Case_Ignorable # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU 116B7 ; Case_Ignorable # Mn TAKRI SIGN NUKTA -1171D..1171F ; Case_Ignorable # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; Case_Ignorable # Mn AHOM CONSONANT SIGN MEDIAL LA +1171F ; Case_Ignorable # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11722..11725 ; Case_Ignorable # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11727..1172B ; Case_Ignorable # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER 1182F..11837 ; Case_Ignorable # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA @@ -3388,12 +3447,17 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 11F36..11F3A ; Case_Ignorable # Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R 11F40 ; Case_Ignorable # Mn KAWI VOWEL SIGN EU 11F42 ; Case_Ignorable # Mn KAWI CONJOINER +11F5A ; Case_Ignorable # Mn KAWI SIGN NUKTA 13430..1343F ; Case_Ignorable # Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE 13440 ; Case_Ignorable # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13447..13455 ; Case_Ignorable # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +1611E..16129 ; Case_Ignorable # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612D..1612F ; Case_Ignorable # Mn [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA 16AF0..16AF4 ; Case_Ignorable # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; Case_Ignorable # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16B40..16B43 ; Case_Ignorable # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM +16D40..16D42 ; Case_Ignorable # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D6B..16D6C ; Case_Ignorable # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16F4F ; Case_Ignorable # Mn MIAO SIGN CONSONANT MODIFIER BAR 16F8F..16F92 ; Case_Ignorable # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16F93..16F9F ; Case_Ignorable # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 @@ -3432,6 +3496,7 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 1E2EC..1E2EF ; Case_Ignorable # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI 1E4EB ; Case_Ignorable # Lm NAG MUNDARI SIGN OJOD 1E4EC..1E4EF ; Case_Ignorable # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH +1E5EE..1E5EF ; Case_Ignorable # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR 1E8D0..1E8D6 ; Case_Ignorable # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS 1E944..1E94A ; Case_Ignorable # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA 1E94B ; Case_Ignorable # Lm ADLAM NASALIZATION MARK @@ -3440,7 +3505,7 @@ E0001 ; Case_Ignorable # Cf LANGUAGE TAG E0020..E007F ; Case_Ignorable # Cf [96] TAG SPACE..CANCEL TAG E0100..E01EF ; Case_Ignorable # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 2707 +# Total code points: 2749 # ================================================ @@ -3724,6 +3789,7 @@ E0100..E01EF ; Case_Ignorable # Mn [240] VARIATION SELECTOR-17..VARIATION SELEC 10C7 ; Changes_When_Lowercased # L& GEORGIAN CAPITAL LETTER YN 10CD ; Changes_When_Lowercased # L& GEORGIAN CAPITAL LETTER AEN 13A0..13F5 ; Changes_When_Lowercased # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV +1C89 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER TJE 1C90..1CBA ; Changes_When_Lowercased # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Changes_When_Lowercased # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1E00 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH RING BELOW @@ -4043,9 +4109,12 @@ A7C0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER OLD POLI A7C2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER ANGLICANA W A7C4..A7C7 ; Changes_When_Lowercased # L& [4] LATIN CAPITAL LETTER C WITH PALATAL HOOK..LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY +A7CB..A7CC ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER RAMS HORN..LATIN CAPITAL LETTER S WITH DIAGONAL STROKE A7D0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER CLOSED INSULAR G A7D6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER SIGMOID S +A7DA ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER LAMBDA +A7DC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F5 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER REVERSED HALF H FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z 10400..10427 ; Changes_When_Lowercased # L& [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW @@ -4055,11 +4124,12 @@ FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTE 1058C..10592 ; Changes_When_Lowercased # L& [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE 10594..10595 ; Changes_When_Lowercased # L& [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE 10C80..10CB2 ; Changes_When_Lowercased # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10D50..10D65 ; Changes_When_Lowercased # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA 118A0..118BF ; Changes_When_Lowercased # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 16E40..16E5F ; Changes_When_Lowercased # L& [32] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN CAPITAL LETTER Y 1E900..1E921 ; Changes_When_Lowercased # L& [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA -# Total code points: 1433 +# Total code points: 1460 # ================================================ @@ -4140,7 +4210,7 @@ FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTE 018C ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH TOPBAR 0192 ; Changes_When_Uppercased # L& LATIN SMALL LETTER F WITH HOOK 0195 ; Changes_When_Uppercased # L& LATIN SMALL LETTER HV -0199..019A ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER L WITH BAR +0199..019B ; Changes_When_Uppercased # L& [3] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER LAMBDA WITH STROKE 019E ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH LONG RIGHT LEG 01A1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH HORN 01A3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER OI @@ -4216,8 +4286,7 @@ FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTE 0259 ; Changes_When_Uppercased # L& LATIN SMALL LETTER SCHWA 025B..025C ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER OPEN E..LATIN SMALL LETTER REVERSED OPEN E 0260..0261 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER G WITH HOOK..LATIN SMALL LETTER SCRIPT G -0263 ; Changes_When_Uppercased # L& LATIN SMALL LETTER GAMMA -0265..0266 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER TURNED H..LATIN SMALL LETTER H WITH HOOK +0263..0266 ; Changes_When_Uppercased # L& [4] LATIN SMALL LETTER GAMMA..LATIN SMALL LETTER H WITH HOOK 0268..026C ; Changes_When_Uppercased # L& [5] LATIN SMALL LETTER I WITH STROKE..LATIN SMALL LETTER L WITH BELT 026F ; Changes_When_Uppercased # L& LATIN SMALL LETTER TURNED M 0271..0272 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER M WITH HOOK..LATIN SMALL LETTER N WITH LEFT HOOK @@ -4357,6 +4426,7 @@ FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTE 10FD..10FF ; Changes_When_Uppercased # L& [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN 13F8..13FD ; Changes_When_Uppercased # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV 1C80..1C88 ; Changes_When_Uppercased # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C8A ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER TJE 1D79 ; Changes_When_Uppercased # L& LATIN SMALL LETTER INSULAR G 1D7D ; Changes_When_Uppercased # L& LATIN SMALL LETTER P WITH STROKE 1D8E ; Changes_When_Uppercased # L& LATIN SMALL LETTER Z WITH PALATAL HOOK @@ -4676,9 +4746,11 @@ A7C1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER OLD POLISH A7C3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER ANGLICANA W A7C8 ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY A7CA ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7CD ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER CLOSED INSULAR G A7D7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER MIDDLE SCOTS S A7D9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER SIGMOID S +A7DB ; Changes_When_Uppercased # L& LATIN SMALL LETTER LAMBDA A7F6 ; Changes_When_Uppercased # L& LATIN SMALL LETTER REVERSED HALF H AB53 ; Changes_When_Uppercased # L& LATIN SMALL LETTER CHI AB70..ABBF ; Changes_When_Uppercased # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA @@ -4692,11 +4764,12 @@ FF41..FF5A ; Changes_When_Uppercased # L& [26] FULLWIDTH LATIN SMALL LETTER 105B3..105B9 ; Changes_When_Uppercased # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; Changes_When_Uppercased # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE 10CC0..10CF2 ; Changes_When_Uppercased # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D70..10D85 ; Changes_When_Uppercased # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118C0..118DF ; Changes_When_Uppercased # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E60..16E7F ; Changes_When_Uppercased # L& [32] MEDEFAIDRIN SMALL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1E922..1E943 ; Changes_When_Uppercased # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 1525 +# Total code points: 1552 # ================================================ @@ -4777,7 +4850,7 @@ FF41..FF5A ; Changes_When_Uppercased # L& [26] FULLWIDTH LATIN SMALL LETTER 018C ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH TOPBAR 0192 ; Changes_When_Titlecased # L& LATIN SMALL LETTER F WITH HOOK 0195 ; Changes_When_Titlecased # L& LATIN SMALL LETTER HV -0199..019A ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER L WITH BAR +0199..019B ; Changes_When_Titlecased # L& [3] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER LAMBDA WITH STROKE 019E ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH LONG RIGHT LEG 01A1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH HORN 01A3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER OI @@ -4854,8 +4927,7 @@ FF41..FF5A ; Changes_When_Uppercased # L& [26] FULLWIDTH LATIN SMALL LETTER 0259 ; Changes_When_Titlecased # L& LATIN SMALL LETTER SCHWA 025B..025C ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER OPEN E..LATIN SMALL LETTER REVERSED OPEN E 0260..0261 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER G WITH HOOK..LATIN SMALL LETTER SCRIPT G -0263 ; Changes_When_Titlecased # L& LATIN SMALL LETTER GAMMA -0265..0266 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER TURNED H..LATIN SMALL LETTER H WITH HOOK +0263..0266 ; Changes_When_Titlecased # L& [4] LATIN SMALL LETTER GAMMA..LATIN SMALL LETTER H WITH HOOK 0268..026C ; Changes_When_Titlecased # L& [5] LATIN SMALL LETTER I WITH STROKE..LATIN SMALL LETTER L WITH BELT 026F ; Changes_When_Titlecased # L& LATIN SMALL LETTER TURNED M 0271..0272 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER M WITH HOOK..LATIN SMALL LETTER N WITH LEFT HOOK @@ -4993,6 +5065,7 @@ FF41..FF5A ; Changes_When_Uppercased # L& [26] FULLWIDTH LATIN SMALL LETTER 0561..0587 ; Changes_When_Titlecased # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN 13F8..13FD ; Changes_When_Titlecased # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV 1C80..1C88 ; Changes_When_Titlecased # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C8A ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER TJE 1D79 ; Changes_When_Titlecased # L& LATIN SMALL LETTER INSULAR G 1D7D ; Changes_When_Titlecased # L& LATIN SMALL LETTER P WITH STROKE 1D8E ; Changes_When_Titlecased # L& LATIN SMALL LETTER Z WITH PALATAL HOOK @@ -5312,9 +5385,11 @@ A7C1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER OLD POLISH A7C3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER ANGLICANA W A7C8 ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY A7CA ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7CD ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER CLOSED INSULAR G A7D7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER MIDDLE SCOTS S A7D9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER SIGMOID S +A7DB ; Changes_When_Titlecased # L& LATIN SMALL LETTER LAMBDA A7F6 ; Changes_When_Titlecased # L& LATIN SMALL LETTER REVERSED HALF H AB53 ; Changes_When_Titlecased # L& LATIN SMALL LETTER CHI AB70..ABBF ; Changes_When_Titlecased # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA @@ -5328,11 +5403,12 @@ FF41..FF5A ; Changes_When_Titlecased # L& [26] FULLWIDTH LATIN SMALL LETTER 105B3..105B9 ; Changes_When_Titlecased # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; Changes_When_Titlecased # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE 10CC0..10CF2 ; Changes_When_Titlecased # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D70..10D85 ; Changes_When_Titlecased # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118C0..118DF ; Changes_When_Titlecased # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E60..16E7F ; Changes_When_Titlecased # L& [32] MEDEFAIDRIN SMALL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1E922..1E943 ; Changes_When_Titlecased # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 1452 +# Total code points: 1479 # ================================================ @@ -5623,7 +5699,7 @@ FF41..FF5A ; Changes_When_Titlecased # L& [26] FULLWIDTH LATIN SMALL LETTER 10C7 ; Changes_When_Casefolded # L& GEORGIAN CAPITAL LETTER YN 10CD ; Changes_When_Casefolded # L& GEORGIAN CAPITAL LETTER AEN 13F8..13FD ; Changes_When_Casefolded # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV -1C80..1C88 ; Changes_When_Casefolded # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C89 ; Changes_When_Casefolded # L& [10] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC CAPITAL LETTER TJE 1C90..1CBA ; Changes_When_Casefolded # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Changes_When_Casefolded # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1E00 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH RING BELOW @@ -5945,9 +6021,12 @@ A7C0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER OLD POLI A7C2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER ANGLICANA W A7C4..A7C7 ; Changes_When_Casefolded # L& [4] LATIN CAPITAL LETTER C WITH PALATAL HOOK..LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY +A7CB..A7CC ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER RAMS HORN..LATIN CAPITAL LETTER S WITH DIAGONAL STROKE A7D0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER CLOSED INSULAR G A7D6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER SIGMOID S +A7DA ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER LAMBDA +A7DC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F5 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER REVERSED HALF H AB70..ABBF ; Changes_When_Casefolded # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA FB00..FB06 ; Changes_When_Casefolded # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST @@ -5960,11 +6039,12 @@ FF21..FF3A ; Changes_When_Casefolded # L& [26] FULLWIDTH LATIN CAPITAL LETTE 1058C..10592 ; Changes_When_Casefolded # L& [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE 10594..10595 ; Changes_When_Casefolded # L& [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE 10C80..10CB2 ; Changes_When_Casefolded # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10D50..10D65 ; Changes_When_Casefolded # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA 118A0..118BF ; Changes_When_Casefolded # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 16E40..16E5F ; Changes_When_Casefolded # L& [32] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN CAPITAL LETTER Y 1E900..1E921 ; Changes_When_Casefolded # L& [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA -# Total code points: 1506 +# Total code points: 1533 # ================================================ @@ -5980,8 +6060,7 @@ FF21..FF3A ; Changes_When_Casefolded # L& [26] FULLWIDTH LATIN CAPITAL LETTE 00D8..00F6 ; Changes_When_Casemapped # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS 00F8..0137 ; Changes_When_Casemapped # L& [64] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER K WITH CEDILLA 0139..018C ; Changes_When_Casemapped # L& [84] LATIN CAPITAL LETTER L WITH ACUTE..LATIN SMALL LETTER D WITH TOPBAR -018E..019A ; Changes_When_Casemapped # L& [13] LATIN CAPITAL LETTER REVERSED E..LATIN SMALL LETTER L WITH BAR -019C..01A9 ; Changes_When_Casemapped # L& [14] LATIN CAPITAL LETTER TURNED M..LATIN CAPITAL LETTER ESH +018E..01A9 ; Changes_When_Casemapped # L& [28] LATIN CAPITAL LETTER REVERSED E..LATIN CAPITAL LETTER ESH 01AC..01B9 ; Changes_When_Casemapped # L& [14] LATIN CAPITAL LETTER T WITH HOOK..LATIN SMALL LETTER EZH REVERSED 01BC..01BD ; Changes_When_Casemapped # L& [2] LATIN CAPITAL LETTER TONE FIVE..LATIN SMALL LETTER TONE FIVE 01BF ; Changes_When_Casemapped # L& LATIN LETTER WYNN @@ -5992,8 +6071,7 @@ FF21..FF3A ; Changes_When_Casefolded # L& [26] FULLWIDTH LATIN CAPITAL LETTE 0259 ; Changes_When_Casemapped # L& LATIN SMALL LETTER SCHWA 025B..025C ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER OPEN E..LATIN SMALL LETTER REVERSED OPEN E 0260..0261 ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER G WITH HOOK..LATIN SMALL LETTER SCRIPT G -0263 ; Changes_When_Casemapped # L& LATIN SMALL LETTER GAMMA -0265..0266 ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER TURNED H..LATIN SMALL LETTER H WITH HOOK +0263..0266 ; Changes_When_Casemapped # L& [4] LATIN SMALL LETTER GAMMA..LATIN SMALL LETTER H WITH HOOK 0268..026C ; Changes_When_Casemapped # L& [5] LATIN SMALL LETTER I WITH STROKE..LATIN SMALL LETTER L WITH BELT 026F ; Changes_When_Casemapped # L& LATIN SMALL LETTER TURNED M 0271..0272 ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER M WITH HOOK..LATIN SMALL LETTER N WITH LEFT HOOK @@ -6027,7 +6105,7 @@ FF21..FF3A ; Changes_When_Casefolded # L& [26] FULLWIDTH LATIN CAPITAL LETTE 10FD..10FF ; Changes_When_Casemapped # L& [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN 13A0..13F5 ; Changes_When_Casemapped # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV 13F8..13FD ; Changes_When_Casemapped # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV -1C80..1C88 ; Changes_When_Casemapped # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; Changes_When_Casemapped # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; Changes_When_Casemapped # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Changes_When_Casemapped # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1D79 ; Changes_When_Casemapped # L& LATIN SMALL LETTER INSULAR G @@ -6078,9 +6156,9 @@ A779..A787 ; Changes_When_Casemapped # L& [15] LATIN CAPITAL LETTER INSULAR A78B..A78D ; Changes_When_Casemapped # L& [3] LATIN CAPITAL LETTER SALTILLO..LATIN CAPITAL LETTER TURNED H A790..A794 ; Changes_When_Casemapped # L& [5] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER C WITH PALATAL HOOK A796..A7AE ; Changes_When_Casemapped # L& [25] LATIN CAPITAL LETTER B WITH FLOURISH..LATIN CAPITAL LETTER SMALL CAPITAL I -A7B0..A7CA ; Changes_When_Casemapped # L& [27] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7B0..A7CD ; Changes_When_Casemapped # L& [30] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; Changes_When_Casemapped # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G -A7D6..A7D9 ; Changes_When_Casemapped # L& [4] LATIN CAPITAL LETTER MIDDLE SCOTS S..LATIN SMALL LETTER SIGMOID S +A7D6..A7DC ; Changes_When_Casemapped # L& [7] LATIN CAPITAL LETTER MIDDLE SCOTS S..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F5..A7F6 ; Changes_When_Casemapped # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H AB53 ; Changes_When_Casemapped # L& LATIN SMALL LETTER CHI AB70..ABBF ; Changes_When_Casemapped # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA @@ -6101,11 +6179,13 @@ FF41..FF5A ; Changes_When_Casemapped # L& [26] FULLWIDTH LATIN SMALL LETTER 105BB..105BC ; Changes_When_Casemapped # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE 10C80..10CB2 ; Changes_When_Casemapped # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US 10CC0..10CF2 ; Changes_When_Casemapped # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D50..10D65 ; Changes_When_Casemapped # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D70..10D85 ; Changes_When_Casemapped # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118A0..118DF ; Changes_When_Casemapped # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E40..16E7F ; Changes_When_Casemapped # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1E900..1E943 ; Changes_When_Casemapped # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 2927 +# Total code points: 2981 # ================================================ @@ -6364,7 +6444,7 @@ FF41..FF5A ; Changes_When_Casemapped # L& [26] FULLWIDTH LATIN SMALL LETTER 1C4D..1C4F ; ID_Start # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA 1C5A..1C77 ; ID_Start # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; ID_Start # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD -1C80..1C88 ; ID_Start # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; ID_Start # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; ID_Start # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; ID_Start # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CE9..1CEC ; ID_Start # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL @@ -6481,10 +6561,10 @@ A771..A787 ; ID_Start # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER I A788 ; ID_Start # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; ID_Start # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; ID_Start # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; ID_Start # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; ID_Start # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; ID_Start # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; ID_Start # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; ID_Start # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; ID_Start # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; ID_Start # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; ID_Start # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; ID_Start # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -6603,6 +6683,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 105A3..105B1 ; ID_Start # L& [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; ID_Start # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; ID_Start # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; ID_Start # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; ID_Start # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; ID_Start # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; ID_Start # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -6639,8 +6720,15 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 10C80..10CB2 ; ID_Start # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US 10CC0..10CF2 ; ID_Start # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US 10D00..10D23 ; ID_Start # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA +10D4A..10D4D ; ID_Start # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; ID_Start # Lm GARAY VOWEL LENGTH MARK +10D4F ; ID_Start # Lo GARAY SUKUN +10D50..10D65 ; ID_Start # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D6F ; ID_Start # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; ID_Start # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 10E80..10EA9 ; ID_Start # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EB0..10EB1 ; ID_Start # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10EC2..10EC4 ; ID_Start # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW 10F00..10F1C ; ID_Start # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; ID_Start # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; ID_Start # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -6679,6 +6767,13 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1133D ; ID_Start # Lo GRANTHA SIGN AVAGRAHA 11350 ; ID_Start # Lo GRANTHA OM 1135D..11361 ; ID_Start # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11380..11389 ; ID_Start # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; ID_Start # Lo TULU-TIGALARI LETTER EE +1138E ; ID_Start # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; ID_Start # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; ID_Start # Lo TULU-TIGALARI SIGN AVAGRAHA +113D1 ; ID_Start # Lo TULU-TIGALARI REPHA +113D3 ; ID_Start # Lo TULU-TIGALARI SIGN PLUTA 11400..11434 ; ID_Start # Lo [53] NEWA LETTER A..NEWA LETTER HA 11447..1144A ; ID_Start # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI 1145F..11461 ; ID_Start # Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA @@ -6713,6 +6808,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 11A5C..11A89 ; ID_Start # Lo [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA 11A9D ; ID_Start # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; ID_Start # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; ID_Start # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO 11C00..11C08 ; ID_Start # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; ID_Start # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C40 ; ID_Start # Lo BHAIKSUKI SIGN AVAGRAHA @@ -6736,7 +6832,9 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 12F90..12FF0 ; ID_Start # Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 13000..1342F ; ID_Start # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D 13441..13446 ; ID_Start # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN +13460..143FA ; ID_Start # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; ID_Start # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; ID_Start # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA 16800..16A38 ; ID_Start # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; ID_Start # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A70..16ABE ; ID_Start # Lo [79] TANGSA LETTER OZ..TANGSA LETTER ZA @@ -6745,6 +6843,9 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 16B40..16B43 ; ID_Start # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM 16B63..16B77 ; ID_Start # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; ID_Start # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; ID_Start # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; ID_Start # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; ID_Start # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16E40..16E7F ; ID_Start # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16F00..16F4A ; ID_Start # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F50 ; ID_Start # Lo MIAO LETTER NASALIZATION @@ -6753,7 +6854,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 16FE3 ; ID_Start # Lm OLD CHINESE ITERATION MARK 17000..187F7 ; ID_Start # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; ID_Start # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; ID_Start # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; ID_Start # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; ID_Start # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; ID_Start # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; ID_Start # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -6809,6 +6910,8 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1E2C0..1E2EB ; ID_Start # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH 1E4D0..1E4EA ; ID_Start # Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL 1E4EB ; ID_Start # Lm NAG MUNDARI SIGN OJOD +1E5D0..1E5ED ; ID_Start # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5F0 ; ID_Start # Lo OL ONAL SIGN HODDOND 1E7E0..1E7E6 ; ID_Start # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; ID_Start # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; ID_Start # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -6859,7 +6962,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 30000..3134A ; ID_Start # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A 31350..323AF ; ID_Start # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF -# Total code points: 136967 +# Total code points: 141269 # ================================================ @@ -6966,7 +7069,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 0860..086A ; ID_Continue # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 0870..0887 ; ID_Continue # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT 0889..088E ; ID_Continue # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL -0898..089F ; ID_Continue # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; ID_Continue # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08A0..08C8 ; ID_Continue # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; ID_Continue # Lm ARABIC SMALL FARSI YEH 08CA..08E1 ; ID_Continue # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA @@ -7399,7 +7502,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1C50..1C59 ; ID_Continue # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE 1C5A..1C77 ; ID_Continue # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; ID_Continue # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD -1C80..1C88 ; ID_Continue # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; ID_Continue # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; ID_Continue # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; ID_Continue # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CD0..1CD2 ; ID_Continue # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA @@ -7543,10 +7646,10 @@ A771..A787 ; ID_Continue # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTE A788 ; ID_Continue # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; ID_Continue # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; ID_Continue # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; ID_Continue # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; ID_Continue # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; ID_Continue # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; ID_Continue # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; ID_Continue # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; ID_Continue # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; ID_Continue # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; ID_Continue # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; ID_Continue # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -7735,6 +7838,7 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 105A3..105B1 ; ID_Continue # L& [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; ID_Continue # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; ID_Continue # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; ID_Continue # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; ID_Continue # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; ID_Continue # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; ID_Continue # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -7779,10 +7883,19 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 10D00..10D23 ; ID_Continue # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA 10D24..10D27 ; ID_Continue # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI 10D30..10D39 ; ID_Continue # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +10D40..10D49 ; ID_Continue # Nd [10] GARAY DIGIT ZERO..GARAY DIGIT NINE +10D4A..10D4D ; ID_Continue # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; ID_Continue # Lm GARAY VOWEL LENGTH MARK +10D4F ; ID_Continue # Lo GARAY SUKUN +10D50..10D65 ; ID_Continue # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D69..10D6D ; ID_Continue # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK +10D6F ; ID_Continue # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; ID_Continue # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 10E80..10EA9 ; ID_Continue # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EAB..10EAC ; ID_Continue # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK 10EB0..10EB1 ; ID_Continue # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE -10EFD..10EFF ; ID_Continue # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EC2..10EC4 ; ID_Continue # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW +10EFC..10EFF ; ID_Continue # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F00..10F1C ; ID_Continue # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; ID_Continue # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; ID_Continue # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -7878,6 +7991,24 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 11362..11363 ; ID_Continue # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C ; ID_Continue # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; ID_Continue # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11380..11389 ; ID_Continue # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; ID_Continue # Lo TULU-TIGALARI LETTER EE +1138E ; ID_Continue # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; ID_Continue # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; ID_Continue # Lo TULU-TIGALARI SIGN AVAGRAHA +113B8..113BA ; ID_Continue # Mc [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II +113BB..113C0 ; ID_Continue # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113C2 ; ID_Continue # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; ID_Continue # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113CA ; ID_Continue # Mc [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; ID_Continue # Mc [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA +113CE ; ID_Continue # Mn TULU-TIGALARI SIGN VIRAMA +113CF ; ID_Continue # Mc TULU-TIGALARI SIGN LOOPED VIRAMA +113D0 ; ID_Continue # Mn TULU-TIGALARI CONJOINER +113D1 ; ID_Continue # Lo TULU-TIGALARI REPHA +113D2 ; ID_Continue # Mn TULU-TIGALARI GEMINATION MARK +113D3 ; ID_Continue # Lo TULU-TIGALARI SIGN PLUTA +113E1..113E2 ; ID_Continue # Mn [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11400..11434 ; ID_Continue # Lo [53] NEWA LETTER A..NEWA LETTER HA 11435..11437 ; ID_Continue # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11438..1143F ; ID_Continue # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI @@ -7929,8 +8060,11 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 116B7 ; ID_Continue # Mn TAKRI SIGN NUKTA 116B8 ; ID_Continue # Lo TAKRI LETTER ARCHAIC KHA 116C0..116C9 ; ID_Continue # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE +116D0..116E3 ; ID_Continue # Nd [20] MYANMAR PAO DIGIT ZERO..MYANMAR EASTERN PWO KAREN DIGIT NINE 11700..1171A ; ID_Continue # Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA -1171D..1171F ; ID_Continue # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; ID_Continue # Mn AHOM CONSONANT SIGN MEDIAL LA +1171E ; ID_Continue # Mc AHOM CONSONANT SIGN MEDIAL RA +1171F ; ID_Continue # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11720..11721 ; ID_Continue # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11722..11725 ; ID_Continue # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11726 ; ID_Continue # Mc AHOM VOWEL SIGN E @@ -7988,6 +8122,8 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 11A98..11A99 ; ID_Continue # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER 11A9D ; ID_Continue # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; ID_Continue # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; ID_Continue # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO +11BF0..11BF9 ; ID_Continue # Nd [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE 11C00..11C08 ; ID_Continue # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; ID_Continue # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C2F ; ID_Continue # Mc BHAIKSUKI VOWEL SIGN AA @@ -8041,6 +8177,7 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 11F41 ; ID_Continue # Mc KAWI SIGN KILLER 11F42 ; ID_Continue # Mn KAWI CONJOINER 11F50..11F59 ; ID_Continue # Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE +11F5A ; ID_Continue # Mn KAWI SIGN NUKTA 11FB0 ; ID_Continue # Lo LISU LETTER YHA 12000..12399 ; ID_Continue # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U 12400..1246E ; ID_Continue # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM @@ -8050,7 +8187,13 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 13440 ; ID_Continue # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13441..13446 ; ID_Continue # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN 13447..13455 ; ID_Continue # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +13460..143FA ; ID_Continue # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; ID_Continue # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; ID_Continue # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA +1611E..16129 ; ID_Continue # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612A..1612C ; ID_Continue # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA +1612D..1612F ; ID_Continue # Mn [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA +16130..16139 ; ID_Continue # Nd [10] GURUNG KHEMA DIGIT ZERO..GURUNG KHEMA DIGIT NINE 16800..16A38 ; ID_Continue # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; ID_Continue # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A60..16A69 ; ID_Continue # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE @@ -8064,6 +8207,10 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 16B50..16B59 ; ID_Continue # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE 16B63..16B77 ; ID_Continue # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; ID_Continue # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; ID_Continue # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; ID_Continue # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; ID_Continue # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT +16D70..16D79 ; ID_Continue # Nd [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE 16E40..16E7F ; ID_Continue # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16F00..16F4A ; ID_Continue # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F4F ; ID_Continue # Mn MIAO SIGN CONSONANT MODIFIER BAR @@ -8077,7 +8224,7 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 16FF0..16FF1 ; ID_Continue # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY 17000..187F7 ; ID_Continue # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; ID_Continue # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; ID_Continue # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; ID_Continue # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; ID_Continue # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; ID_Continue # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; ID_Continue # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -8092,6 +8239,7 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 1BC80..1BC88 ; ID_Continue # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL 1BC90..1BC99 ; ID_Continue # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW 1BC9D..1BC9E ; ID_Continue # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1CCF0..1CCF9 ; ID_Continue # Nd [10] OUTLINED DIGIT ZERO..OUTLINED DIGIT NINE 1CF00..1CF2D ; ID_Continue # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT 1CF30..1CF46 ; ID_Continue # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG 1D165..1D166 ; ID_Continue # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM @@ -8163,6 +8311,10 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 1E4EB ; ID_Continue # Lm NAG MUNDARI SIGN OJOD 1E4EC..1E4EF ; ID_Continue # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH 1E4F0..1E4F9 ; ID_Continue # Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE +1E5D0..1E5ED ; ID_Continue # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5EE..1E5EF ; ID_Continue # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR +1E5F0 ; ID_Continue # Lo OL ONAL SIGN HODDOND +1E5F1..1E5FA ; ID_Continue # Nd [10] OL ONAL DIGIT ZERO..OL ONAL DIGIT NINE 1E7E0..1E7E6 ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; ID_Continue # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; ID_Continue # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -8218,7 +8370,7 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 31350..323AF ; ID_Continue # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF E0100..E01EF ; ID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 140108 +# Total code points: 144541 # ================================================ @@ -8474,7 +8626,7 @@ E0100..E01EF ; ID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR 1C4D..1C4F ; XID_Start # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA 1C5A..1C77 ; XID_Start # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; XID_Start # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD -1C80..1C88 ; XID_Start # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; XID_Start # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; XID_Start # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; XID_Start # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CE9..1CEC ; XID_Start # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL @@ -8590,10 +8742,10 @@ A771..A787 ; XID_Start # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER A788 ; XID_Start # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; XID_Start # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; XID_Start # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; XID_Start # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; XID_Start # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; XID_Start # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; XID_Start # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; XID_Start # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; XID_Start # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; XID_Start # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; XID_Start # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; XID_Start # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -8717,6 +8869,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 105A3..105B1 ; XID_Start # L& [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; XID_Start # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; XID_Start # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; XID_Start # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; XID_Start # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; XID_Start # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; XID_Start # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -8753,8 +8906,15 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 10C80..10CB2 ; XID_Start # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US 10CC0..10CF2 ; XID_Start # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US 10D00..10D23 ; XID_Start # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA +10D4A..10D4D ; XID_Start # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; XID_Start # Lm GARAY VOWEL LENGTH MARK +10D4F ; XID_Start # Lo GARAY SUKUN +10D50..10D65 ; XID_Start # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D6F ; XID_Start # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; XID_Start # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 10E80..10EA9 ; XID_Start # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EB0..10EB1 ; XID_Start # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10EC2..10EC4 ; XID_Start # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW 10F00..10F1C ; XID_Start # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; XID_Start # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; XID_Start # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -8793,6 +8953,13 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 1133D ; XID_Start # Lo GRANTHA SIGN AVAGRAHA 11350 ; XID_Start # Lo GRANTHA OM 1135D..11361 ; XID_Start # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11380..11389 ; XID_Start # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; XID_Start # Lo TULU-TIGALARI LETTER EE +1138E ; XID_Start # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; XID_Start # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; XID_Start # Lo TULU-TIGALARI SIGN AVAGRAHA +113D1 ; XID_Start # Lo TULU-TIGALARI REPHA +113D3 ; XID_Start # Lo TULU-TIGALARI SIGN PLUTA 11400..11434 ; XID_Start # Lo [53] NEWA LETTER A..NEWA LETTER HA 11447..1144A ; XID_Start # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI 1145F..11461 ; XID_Start # Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA @@ -8827,6 +8994,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 11A5C..11A89 ; XID_Start # Lo [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA 11A9D ; XID_Start # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; XID_Start # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; XID_Start # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO 11C00..11C08 ; XID_Start # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; XID_Start # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C40 ; XID_Start # Lo BHAIKSUKI SIGN AVAGRAHA @@ -8850,7 +9018,9 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 12F90..12FF0 ; XID_Start # Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 13000..1342F ; XID_Start # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D 13441..13446 ; XID_Start # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN +13460..143FA ; XID_Start # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; XID_Start # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; XID_Start # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA 16800..16A38 ; XID_Start # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; XID_Start # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A70..16ABE ; XID_Start # Lo [79] TANGSA LETTER OZ..TANGSA LETTER ZA @@ -8859,6 +9029,9 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 16B40..16B43 ; XID_Start # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM 16B63..16B77 ; XID_Start # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; XID_Start # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; XID_Start # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; XID_Start # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; XID_Start # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16E40..16E7F ; XID_Start # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16F00..16F4A ; XID_Start # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F50 ; XID_Start # Lo MIAO LETTER NASALIZATION @@ -8867,7 +9040,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 16FE3 ; XID_Start # Lm OLD CHINESE ITERATION MARK 17000..187F7 ; XID_Start # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; XID_Start # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; XID_Start # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; XID_Start # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; XID_Start # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; XID_Start # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; XID_Start # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -8923,6 +9096,8 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 1E2C0..1E2EB ; XID_Start # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH 1E4D0..1E4EA ; XID_Start # Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL 1E4EB ; XID_Start # Lm NAG MUNDARI SIGN OJOD +1E5D0..1E5ED ; XID_Start # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5F0 ; XID_Start # Lo OL ONAL SIGN HODDOND 1E7E0..1E7E6 ; XID_Start # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; XID_Start # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; XID_Start # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -8973,7 +9148,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 30000..3134A ; XID_Start # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A 31350..323AF ; XID_Start # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF -# Total code points: 136944 +# Total code points: 141246 # ================================================ @@ -9076,7 +9251,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 0860..086A ; XID_Continue # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 0870..0887 ; XID_Continue # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT 0889..088E ; XID_Continue # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL -0898..089F ; XID_Continue # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; XID_Continue # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08A0..08C8 ; XID_Continue # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; XID_Continue # Lm ARABIC SMALL FARSI YEH 08CA..08E1 ; XID_Continue # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA @@ -9509,7 +9684,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 1C50..1C59 ; XID_Continue # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE 1C5A..1C77 ; XID_Continue # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; XID_Continue # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD -1C80..1C88 ; XID_Continue # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; XID_Continue # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; XID_Continue # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; XID_Continue # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CD0..1CD2 ; XID_Continue # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA @@ -9652,10 +9827,10 @@ A771..A787 ; XID_Continue # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETT A788 ; XID_Continue # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; XID_Continue # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; XID_Continue # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; XID_Continue # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; XID_Continue # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; XID_Continue # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; XID_Continue # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; XID_Continue # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; XID_Continue # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; XID_Continue # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; XID_Continue # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; XID_Continue # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -9850,6 +10025,7 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 105A3..105B1 ; XID_Continue # L& [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; XID_Continue # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; XID_Continue # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; XID_Continue # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; XID_Continue # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; XID_Continue # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; XID_Continue # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -9894,10 +10070,19 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 10D00..10D23 ; XID_Continue # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA 10D24..10D27 ; XID_Continue # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI 10D30..10D39 ; XID_Continue # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +10D40..10D49 ; XID_Continue # Nd [10] GARAY DIGIT ZERO..GARAY DIGIT NINE +10D4A..10D4D ; XID_Continue # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; XID_Continue # Lm GARAY VOWEL LENGTH MARK +10D4F ; XID_Continue # Lo GARAY SUKUN +10D50..10D65 ; XID_Continue # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D69..10D6D ; XID_Continue # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK +10D6F ; XID_Continue # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; XID_Continue # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 10E80..10EA9 ; XID_Continue # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EAB..10EAC ; XID_Continue # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK 10EB0..10EB1 ; XID_Continue # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE -10EFD..10EFF ; XID_Continue # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EC2..10EC4 ; XID_Continue # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW +10EFC..10EFF ; XID_Continue # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F00..10F1C ; XID_Continue # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; XID_Continue # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; XID_Continue # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -9993,6 +10178,24 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 11362..11363 ; XID_Continue # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C ; XID_Continue # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; XID_Continue # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11380..11389 ; XID_Continue # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; XID_Continue # Lo TULU-TIGALARI LETTER EE +1138E ; XID_Continue # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; XID_Continue # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; XID_Continue # Lo TULU-TIGALARI SIGN AVAGRAHA +113B8..113BA ; XID_Continue # Mc [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II +113BB..113C0 ; XID_Continue # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113C2 ; XID_Continue # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; XID_Continue # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113CA ; XID_Continue # Mc [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; XID_Continue # Mc [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA +113CE ; XID_Continue # Mn TULU-TIGALARI SIGN VIRAMA +113CF ; XID_Continue # Mc TULU-TIGALARI SIGN LOOPED VIRAMA +113D0 ; XID_Continue # Mn TULU-TIGALARI CONJOINER +113D1 ; XID_Continue # Lo TULU-TIGALARI REPHA +113D2 ; XID_Continue # Mn TULU-TIGALARI GEMINATION MARK +113D3 ; XID_Continue # Lo TULU-TIGALARI SIGN PLUTA +113E1..113E2 ; XID_Continue # Mn [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11400..11434 ; XID_Continue # Lo [53] NEWA LETTER A..NEWA LETTER HA 11435..11437 ; XID_Continue # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11438..1143F ; XID_Continue # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI @@ -10044,8 +10247,11 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 116B7 ; XID_Continue # Mn TAKRI SIGN NUKTA 116B8 ; XID_Continue # Lo TAKRI LETTER ARCHAIC KHA 116C0..116C9 ; XID_Continue # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE +116D0..116E3 ; XID_Continue # Nd [20] MYANMAR PAO DIGIT ZERO..MYANMAR EASTERN PWO KAREN DIGIT NINE 11700..1171A ; XID_Continue # Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA -1171D..1171F ; XID_Continue # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; XID_Continue # Mn AHOM CONSONANT SIGN MEDIAL LA +1171E ; XID_Continue # Mc AHOM CONSONANT SIGN MEDIAL RA +1171F ; XID_Continue # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11720..11721 ; XID_Continue # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11722..11725 ; XID_Continue # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11726 ; XID_Continue # Mc AHOM VOWEL SIGN E @@ -10103,6 +10309,8 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 11A98..11A99 ; XID_Continue # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER 11A9D ; XID_Continue # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; XID_Continue # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; XID_Continue # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO +11BF0..11BF9 ; XID_Continue # Nd [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE 11C00..11C08 ; XID_Continue # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; XID_Continue # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C2F ; XID_Continue # Mc BHAIKSUKI VOWEL SIGN AA @@ -10156,6 +10364,7 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 11F41 ; XID_Continue # Mc KAWI SIGN KILLER 11F42 ; XID_Continue # Mn KAWI CONJOINER 11F50..11F59 ; XID_Continue # Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE +11F5A ; XID_Continue # Mn KAWI SIGN NUKTA 11FB0 ; XID_Continue # Lo LISU LETTER YHA 12000..12399 ; XID_Continue # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U 12400..1246E ; XID_Continue # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM @@ -10165,7 +10374,13 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 13440 ; XID_Continue # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13441..13446 ; XID_Continue # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN 13447..13455 ; XID_Continue # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +13460..143FA ; XID_Continue # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; XID_Continue # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; XID_Continue # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA +1611E..16129 ; XID_Continue # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612A..1612C ; XID_Continue # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA +1612D..1612F ; XID_Continue # Mn [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA +16130..16139 ; XID_Continue # Nd [10] GURUNG KHEMA DIGIT ZERO..GURUNG KHEMA DIGIT NINE 16800..16A38 ; XID_Continue # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; XID_Continue # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A60..16A69 ; XID_Continue # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE @@ -10179,6 +10394,10 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 16B50..16B59 ; XID_Continue # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE 16B63..16B77 ; XID_Continue # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; XID_Continue # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; XID_Continue # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; XID_Continue # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; XID_Continue # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT +16D70..16D79 ; XID_Continue # Nd [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE 16E40..16E7F ; XID_Continue # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16F00..16F4A ; XID_Continue # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F4F ; XID_Continue # Mn MIAO SIGN CONSONANT MODIFIER BAR @@ -10192,7 +10411,7 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 16FF0..16FF1 ; XID_Continue # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY 17000..187F7 ; XID_Continue # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; XID_Continue # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; XID_Continue # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; XID_Continue # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; XID_Continue # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; XID_Continue # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; XID_Continue # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -10207,6 +10426,7 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 1BC80..1BC88 ; XID_Continue # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL 1BC90..1BC99 ; XID_Continue # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW 1BC9D..1BC9E ; XID_Continue # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1CCF0..1CCF9 ; XID_Continue # Nd [10] OUTLINED DIGIT ZERO..OUTLINED DIGIT NINE 1CF00..1CF2D ; XID_Continue # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT 1CF30..1CF46 ; XID_Continue # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG 1D165..1D166 ; XID_Continue # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM @@ -10278,6 +10498,10 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 1E4EB ; XID_Continue # Lm NAG MUNDARI SIGN OJOD 1E4EC..1E4EF ; XID_Continue # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH 1E4F0..1E4F9 ; XID_Continue # Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE +1E5D0..1E5ED ; XID_Continue # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5EE..1E5EF ; XID_Continue # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR +1E5F0 ; XID_Continue # Lo OL ONAL SIGN HODDOND +1E5F1..1E5FA ; XID_Continue # Nd [10] OL ONAL DIGIT ZERO..OL ONAL DIGIT NINE 1E7E0..1E7E6 ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; XID_Continue # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; XID_Continue # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -10333,7 +10557,7 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 31350..323AF ; XID_Continue # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF E0100..E01EF ; XID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 140089 +# Total code points: 144522 # ================================================ @@ -10418,7 +10642,7 @@ E01F0..E0FFF ; Default_Ignorable_Code_Point # Cn [3600] ........ 086B..086F ; Cn # [5] .. 088F ; Cn # -0892..0897 ; Cn # [6] .. +0892..0896 ; Cn # [5] .. 0984 ; Cn # 098D..098E ; Cn # [2] .. 0991..0992 ; Cn # [2] .. @@ -229,12 +229,11 @@ 1A9A..1A9F ; Cn # [6] .. 1AAE..1AAF ; Cn # [2] .. 1ACF..1AFF ; Cn # [49] .. -1B4D..1B4F ; Cn # [3] .. -1B7F ; Cn # +1B4D ; Cn # 1BF4..1BFB ; Cn # [8] .. 1C38..1C3A ; Cn # [3] .. 1C4A..1C4C ; Cn # [3] .. -1C89..1C8F ; Cn # [7] .. +1C8B..1C8F ; Cn # [5] .. 1CBB..1CBC ; Cn # [2] .. 1CC8..1CCF ; Cn # [8] .. 1CFB..1CFF ; Cn # [5] .. @@ -261,7 +260,7 @@ 20C1..20CF ; Cn # [15] .. 20F1..20FF ; Cn # [15] .. 218C..218F ; Cn # [4] .. -2427..243F ; Cn # [25] .. +242A..243F ; Cn # [22] .. 244B..245F ; Cn # [21] .. 2B74..2B75 ; Cn # [2] .. 2B96 ; Cn # @@ -289,16 +288,16 @@ 3100..3104 ; Cn # [5] .. 3130 ; Cn # 318F ; Cn # -31E4..31EE ; Cn # [11] .. +31E6..31EE ; Cn # [9] .. 321F ; Cn # A48D..A48F ; Cn # [3] .. A4C7..A4CF ; Cn # [9] .. A62C..A63F ; Cn # [20] .. A6F8..A6FF ; Cn # [8] .. -A7CB..A7CF ; Cn # [5] .. +A7CE..A7CF ; Cn # [2] .. A7D2 ; Cn # A7D4 ; Cn # -A7DA..A7F1 ; Cn # [24] .. +A7DD..A7F1 ; Cn # [21] .. A82D..A82F ; Cn # [3] .. A83A..A83F ; Cn # [6] .. A878..A87F ; Cn # [8] .. @@ -388,7 +387,8 @@ FFFE..FFFF ; Cn # [2] .. 105A2 ; Cn # 105B2 ; Cn # 105BA ; Cn # -105BD..105FF ; Cn # [67] .. +105BD..105BF ; Cn # [3] .. +105F4..105FF ; Cn # [12] .. 10737..1073F ; Cn # [9] .. 10756..1075F ; Cn # [10] .. 10768..1077F ; Cn # [24] .. @@ -431,11 +431,15 @@ FFFE..FFFF ; Cn # [2] .. 10CB3..10CBF ; Cn # [13] .. 10CF3..10CF9 ; Cn # [7] .. 10D28..10D2F ; Cn # [8] .. -10D3A..10E5F ; Cn # [294] .. +10D3A..10D3F ; Cn # [6] .. +10D66..10D68 ; Cn # [3] .. +10D86..10D8D ; Cn # [8] .. +10D90..10E5F ; Cn # [208] .. 10E7F ; Cn # 10EAA ; Cn # 10EAE..10EAF ; Cn # [2] .. -10EB2..10EFC ; Cn # [75] .. +10EB2..10EC1 ; Cn # [16] .. +10EC5..10EFB ; Cn # [55] .. 10F28..10F2F ; Cn # [8] .. 10F5A..10F6F ; Cn # [22] .. 10F8A..10FAF ; Cn # [38] .. @@ -475,7 +479,18 @@ FFFE..FFFF ; Cn # [2] .. 11358..1135C ; Cn # [5] .. 11364..11365 ; Cn # [2] .. 1136D..1136F ; Cn # [3] .. -11375..113FF ; Cn # [139] .. +11375..1137F ; Cn # [11] .. +1138A ; Cn # +1138C..1138D ; Cn # [2] .. +1138F ; Cn # +113B6 ; Cn # +113C1 ; Cn # +113C3..113C4 ; Cn # [2] .. +113C6 ; Cn # +113CB ; Cn # +113D6 ; Cn # +113D9..113E0 ; Cn # [8] .. +113E3..113FF ; Cn # [29] .. 1145C ; Cn # 11462..1147F ; Cn # [30] .. 114C8..114CF ; Cn # [8] .. @@ -486,7 +501,8 @@ FFFE..FFFF ; Cn # [2] .. 1165A..1165F ; Cn # [6] .. 1166D..1167F ; Cn # [19] .. 116BA..116BF ; Cn # [6] .. -116CA..116FF ; Cn # [54] .. +116CA..116CF ; Cn # [6] .. +116E4..116FF ; Cn # [28] .. 1171B..1171C ; Cn # [2] .. 1172C..1172F ; Cn # [4] .. 11747..117FF ; Cn # [185] .. @@ -506,7 +522,9 @@ FFFE..FFFF ; Cn # [2] .. 11A48..11A4F ; Cn # [8] .. 11AA3..11AAF ; Cn # [13] .. 11AF9..11AFF ; Cn # [7] .. -11B0A..11BFF ; Cn # [246] .. +11B0A..11BBF ; Cn # [182] .. +11BE2..11BEF ; Cn # [14] .. +11BFA..11BFF ; Cn # [6] .. 11C09 ; Cn # 11C37 ; Cn # 11C46..11C4F ; Cn # [10] .. @@ -530,7 +548,7 @@ FFFE..FFFF ; Cn # [2] .. 11EF9..11EFF ; Cn # [7] .. 11F11 ; Cn # 11F3B..11F3D ; Cn # [3] .. -11F5A..11FAF ; Cn # [86] .. +11F5B..11FAF ; Cn # [85] .. 11FB1..11FBF ; Cn # [15] .. 11FF2..11FFE ; Cn # [13] .. 1239A..123FF ; Cn # [102] .. @@ -538,8 +556,10 @@ FFFE..FFFF ; Cn # [2] .. 12475..1247F ; Cn # [11] .. 12544..12F8F ; Cn # [2636] .. 12FF3..12FFF ; Cn # [13] .. -13456..143FF ; Cn # [4010] .. -14647..167FF ; Cn # [8633] .. +13456..1345F ; Cn # [10] .. +143FB..143FF ; Cn # [5] .. +14647..160FF ; Cn # [6841] .. +1613A..167FF ; Cn # [1734] .. 16A39..16A3F ; Cn # [7] .. 16A5F ; Cn # 16A6A..16A6D ; Cn # [4] .. @@ -551,7 +571,8 @@ FFFE..FFFF ; Cn # [2] .. 16B5A ; Cn # 16B62 ; Cn # 16B78..16B7C ; Cn # [5] .. -16B90..16E3F ; Cn # [688] .. +16B90..16D3F ; Cn # [432] .. +16D7A..16E3F ; Cn # [198] .. 16E9B..16EFF ; Cn # [101] .. 16F4B..16F4E ; Cn # [4] .. 16F88..16F8E ; Cn # [7] .. @@ -559,7 +580,7 @@ FFFE..FFFF ; Cn # [2] .. 16FE5..16FEF ; Cn # [11] .. 16FF2..16FFF ; Cn # [14] .. 187F8..187FF ; Cn # [8] .. -18CD6..18CFF ; Cn # [42] .. +18CD6..18CFE ; Cn # [41] .. 18D09..1AFEF ; Cn # [8935] .. 1AFF4 ; Cn # 1AFFC ; Cn # @@ -574,7 +595,9 @@ FFFE..FFFF ; Cn # [2] .. 1BC7D..1BC7F ; Cn # [3] .. 1BC89..1BC8F ; Cn # [7] .. 1BC9A..1BC9B ; Cn # [2] .. -1BCA4..1CEFF ; Cn # [4700] .. +1BCA4..1CBFF ; Cn # [3932] .. +1CCFA..1CCFF ; Cn # [6] .. +1CEB4..1CEFF ; Cn # [76] .. 1CF2E..1CF2F ; Cn # [2] .. 1CF47..1CF4F ; Cn # [9] .. 1CFC4..1CFFF ; Cn # [60] .. @@ -625,7 +648,9 @@ FFFE..FFFF ; Cn # [2] .. 1E2AF..1E2BF ; Cn # [17] .. 1E2FA..1E2FE ; Cn # [5] .. 1E300..1E4CF ; Cn # [464] .. -1E4FA..1E7DF ; Cn # [742] .. +1E4FA..1E5CF ; Cn # [214] .. +1E5FB..1E5FE ; Cn # [4] .. +1E600..1E7DF ; Cn # [480] .. 1E7E7 ; Cn # 1E7EC ; Cn # 1E7EF ; Cn # @@ -695,18 +720,17 @@ FFFE..FFFF ; Cn # [2] .. 1F85A..1F85F ; Cn # [6] .. 1F888..1F88F ; Cn # [8] .. 1F8AE..1F8AF ; Cn # [2] .. -1F8B2..1F8FF ; Cn # [78] .. +1F8BC..1F8BF ; Cn # [4] .. +1F8C2..1F8FF ; Cn # [62] .. 1FA54..1FA5F ; Cn # [12] .. 1FA6E..1FA6F ; Cn # [2] .. 1FA7D..1FA7F ; Cn # [3] .. -1FA89..1FA8F ; Cn # [7] .. -1FABE ; Cn # -1FAC6..1FACD ; Cn # [8] .. -1FADC..1FADF ; Cn # [4] .. -1FAE9..1FAEF ; Cn # [7] .. +1FA8A..1FA8E ; Cn # [5] .. +1FAC7..1FACD ; Cn # [7] .. +1FADD..1FADE ; Cn # [2] .. +1FAEA..1FAEF ; Cn # [6] .. 1FAF9..1FAFF ; Cn # [7] .. 1FB93 ; Cn # -1FBCB..1FBEF ; Cn # [37] .. 1FBFA..1FFFF ; Cn # [1030] .. 2A6E0..2A6FF ; Cn # [32] .. 2B73A..2B73F ; Cn # [6] .. @@ -723,7 +747,7 @@ E01F0..EFFFF ; Cn # [65040] .. FFFFE..FFFFF ; Cn # [2] .. 10FFFE..10FFFF; Cn # [2] .. -# Total code points: 824718 +# Total code points: 819533 # ================================================ @@ -1005,6 +1029,7 @@ FFFFE..FFFFF ; Cn # [2] .. 10C7 ; Lu # GEORGIAN CAPITAL LETTER YN 10CD ; Lu # GEORGIAN CAPITAL LETTER AEN 13A0..13F5 ; Lu # [86] CHEROKEE LETTER A..CHEROKEE LETTER MV +1C89 ; Lu # CYRILLIC CAPITAL LETTER TJE 1C90..1CBA ; Lu # [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; Lu # [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1E00 ; Lu # LATIN CAPITAL LETTER A WITH RING BELOW @@ -1329,9 +1354,12 @@ A7C0 ; Lu # LATIN CAPITAL LETTER OLD POLISH O A7C2 ; Lu # LATIN CAPITAL LETTER ANGLICANA W A7C4..A7C7 ; Lu # [4] LATIN CAPITAL LETTER C WITH PALATAL HOOK..LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9 ; Lu # LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY +A7CB..A7CC ; Lu # [2] LATIN CAPITAL LETTER RAMS HORN..LATIN CAPITAL LETTER S WITH DIAGONAL STROKE A7D0 ; Lu # LATIN CAPITAL LETTER CLOSED INSULAR G A7D6 ; Lu # LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8 ; Lu # LATIN CAPITAL LETTER SIGMOID S +A7DA ; Lu # LATIN CAPITAL LETTER LAMBDA +A7DC ; Lu # LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F5 ; Lu # LATIN CAPITAL LETTER REVERSED HALF H FF21..FF3A ; Lu # [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z 10400..10427 ; Lu # [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW @@ -1341,6 +1369,7 @@ FF21..FF3A ; Lu # [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAP 1058C..10592 ; Lu # [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE 10594..10595 ; Lu # [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE 10C80..10CB2 ; Lu # [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10D50..10D65 ; Lu # [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA 118A0..118BF ; Lu # [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 16E40..16E5F ; Lu # [32] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN CAPITAL LETTER Y 1D400..1D419 ; Lu # [26] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL BOLD CAPITAL Z @@ -1376,7 +1405,7 @@ FF21..FF3A ; Lu # [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAP 1D7CA ; Lu # MATHEMATICAL BOLD CAPITAL DIGAMMA 1E900..1E921 ; Lu # [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA -# Total code points: 1831 +# Total code points: 1858 # ================================================ @@ -1656,6 +1685,7 @@ FF21..FF3A ; Lu # [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAP 10FD..10FF ; Ll # [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN 13F8..13FD ; Ll # [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV 1C80..1C88 ; Ll # [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C8A ; Ll # CYRILLIC SMALL LETTER TJE 1D00..1D2B ; Ll # [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL 1D6B..1D77 ; Ll # [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G 1D79..1D9A ; Ll # [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK @@ -1986,11 +2016,13 @@ A7C1 ; Ll # LATIN SMALL LETTER OLD POLISH O A7C3 ; Ll # LATIN SMALL LETTER ANGLICANA W A7C8 ; Ll # LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY A7CA ; Ll # LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7CD ; Ll # LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D1 ; Ll # LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; Ll # LATIN SMALL LETTER DOUBLE THORN A7D5 ; Ll # LATIN SMALL LETTER DOUBLE WYNN A7D7 ; Ll # LATIN SMALL LETTER MIDDLE SCOTS S A7D9 ; Ll # LATIN SMALL LETTER SIGMOID S +A7DB ; Ll # LATIN SMALL LETTER LAMBDA A7F6 ; Ll # LATIN SMALL LETTER REVERSED HALF H A7FA ; Ll # LATIN LETTER SMALL CAPITAL TURNED M AB30..AB5A ; Ll # [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG @@ -2006,6 +2038,7 @@ FF41..FF5A ; Ll # [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL 105B3..105B9 ; Ll # [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; Ll # [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE 10CC0..10CF2 ; Ll # [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D70..10D85 ; Ll # [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118C0..118DF ; Ll # [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E60..16E7F ; Ll # [32] MEDEFAIDRIN SMALL LETTER M..MEDEFAIDRIN SMALL LETTER Y 1D41A..1D433 ; Ll # [26] MATHEMATICAL BOLD SMALL A..MATHEMATICAL BOLD SMALL Z @@ -2041,7 +2074,7 @@ FF41..FF5A ; Ll # [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL 1DF25..1DF2A ; Ll # [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK 1E922..1E943 ; Ll # [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 2233 +# Total code points: 2258 # ================================================ @@ -2124,7 +2157,11 @@ FF9E..FF9F ; Lm # [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAK 10780..10785 ; Lm # [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK 10787..107B0 ; Lm # [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK 107B2..107BA ; Lm # [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL +10D4E ; Lm # GARAY VOWEL LENGTH MARK +10D6F ; Lm # GARAY REDUPLICATION MARK 16B40..16B43 ; Lm # [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM +16D40..16D42 ; Lm # [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D6B..16D6C ; Lm # [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16F93..16F9F ; Lm # [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 16FE0..16FE1 ; Lm # [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK 16FE3 ; Lm # OLD CHINESE ITERATION MARK @@ -2136,7 +2173,7 @@ FF9E..FF9F ; Lm # [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAK 1E4EB ; Lm # NAG MUNDARI SIGN OJOD 1E94B ; Lm # ADLAM NASALIZATION MARK -# Total code points: 397 +# Total code points: 404 # ================================================ @@ -2451,6 +2488,7 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 10450..1049D ; Lo # [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO 10500..10527 ; Lo # [40] ELBASAN LETTER A..ELBASAN LETTER KHE 10530..10563 ; Lo # [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW +105C0..105F3 ; Lo # [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; Lo # [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; Lo # [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; Lo # [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -2482,8 +2520,11 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 10B80..10B91 ; Lo # [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW 10C00..10C48 ; Lo # [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH 10D00..10D23 ; Lo # [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA +10D4A..10D4D ; Lo # [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4F ; Lo # GARAY SUKUN 10E80..10EA9 ; Lo # [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EB0..10EB1 ; Lo # [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10EC2..10EC4 ; Lo # [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW 10F00..10F1C ; Lo # [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; Lo # OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; Lo # [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -2522,6 +2563,13 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 1133D ; Lo # GRANTHA SIGN AVAGRAHA 11350 ; Lo # GRANTHA OM 1135D..11361 ; Lo # [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11380..11389 ; Lo # [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; Lo # TULU-TIGALARI LETTER EE +1138E ; Lo # TULU-TIGALARI LETTER AI +11390..113B5 ; Lo # [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; Lo # TULU-TIGALARI SIGN AVAGRAHA +113D1 ; Lo # TULU-TIGALARI REPHA +113D3 ; Lo # TULU-TIGALARI SIGN PLUTA 11400..11434 ; Lo # [53] NEWA LETTER A..NEWA LETTER HA 11447..1144A ; Lo # [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI 1145F..11461 ; Lo # [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA @@ -2555,6 +2603,7 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 11A5C..11A89 ; Lo # [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA 11A9D ; Lo # SOYOMBO MARK PLUTA 11AB0..11AF8 ; Lo # [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11BC0..11BE0 ; Lo # [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO 11C00..11C08 ; Lo # [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; Lo # [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C40 ; Lo # BHAIKSUKI SIGN AVAGRAHA @@ -2577,7 +2626,9 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 12F90..12FF0 ; Lo # [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 13000..1342F ; Lo # [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D 13441..13446 ; Lo # [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN +13460..143FA ; Lo # [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; Lo # [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; Lo # [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA 16800..16A38 ; Lo # [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; Lo # [31] MRO LETTER TA..MRO LETTER TEK 16A70..16ABE ; Lo # [79] TANGSA LETTER OZ..TANGSA LETTER ZA @@ -2585,11 +2636,12 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 16B00..16B2F ; Lo # [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU 16B63..16B77 ; Lo # [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; Lo # [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D43..16D6A ; Lo # [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU 16F00..16F4A ; Lo # [75] MIAO LETTER PA..MIAO LETTER RTE 16F50 ; Lo # MIAO LETTER NASALIZATION 17000..187F7 ; Lo # [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18CD5 ; Lo # [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; Lo # [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +18CFF..18D08 ; Lo # [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 1B000..1B122 ; Lo # [291] KATAKANA LETTER ARCHAIC E..KATAKANA LETTER ARCHAIC WU 1B132 ; Lo # HIRAGANA LETTER SMALL KO 1B150..1B152 ; Lo # [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO @@ -2606,6 +2658,8 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 1E290..1E2AD ; Lo # [30] TOTO LETTER PA..TOTO LETTER A 1E2C0..1E2EB ; Lo # [44] WANCHO LETTER AA..WANCHO LETTER YIH 1E4D0..1E4EA ; Lo # [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL +1E5D0..1E5ED ; Lo # [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5F0 ; Lo # OL ONAL SIGN HODDOND 1E7E0..1E7E6 ; Lo # [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; Lo # [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; Lo # [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -2654,7 +2708,7 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 30000..3134A ; Lo # [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A 31350..323AF ; Lo # [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF -# Total code points: 132234 +# Total code points: 136477 # ================================================ @@ -2684,7 +2738,7 @@ FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I 0825..0827 ; Mn # [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082D ; Mn # [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA 0859..085B ; Mn # [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK -0898..089F ; Mn # [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; Mn # [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08CA..08E1 ; Mn # [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA 08E3..0902 ; Mn # [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA 093A ; Mn # DEVANAGARI VOWEL SIGN OE @@ -2882,8 +2936,9 @@ FE20..FE2F ; Mn # [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITL 10A3F ; Mn # KHAROSHTHI VIRAMA 10AE5..10AE6 ; Mn # [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW 10D24..10D27 ; Mn # [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D69..10D6D ; Mn # [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK 10EAB..10EAC ; Mn # [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK -10EFD..10EFF ; Mn # [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EFC..10EFF ; Mn # [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F46..10F50 ; Mn # [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW 10F82..10F85 ; Mn # [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW 11001 ; Mn # BRAHMI SIGN ANUSVARA @@ -2914,6 +2969,11 @@ FE20..FE2F ; Mn # [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITL 11340 ; Mn # GRANTHA VOWEL SIGN II 11366..1136C ; Mn # [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; Mn # [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +113BB..113C0 ; Mn # [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113CE ; Mn # TULU-TIGALARI SIGN VIRAMA +113D0 ; Mn # TULU-TIGALARI CONJOINER +113D2 ; Mn # TULU-TIGALARI GEMINATION MARK +113E1..113E2 ; Mn # [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11438..1143F ; Mn # [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI 11442..11444 ; Mn # [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA 11446 ; Mn # NEWA SIGN NUKTA @@ -2933,7 +2993,8 @@ FE20..FE2F ; Mn # [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITL 116AD ; Mn # TAKRI VOWEL SIGN AA 116B0..116B5 ; Mn # [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU 116B7 ; Mn # TAKRI SIGN NUKTA -1171D..1171F ; Mn # [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; Mn # AHOM CONSONANT SIGN MEDIAL LA +1171F ; Mn # AHOM CONSONANT SIGN MEDIAL LIGATING RA 11722..11725 ; Mn # [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11727..1172B ; Mn # [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER 1182F..11837 ; Mn # [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA @@ -2972,8 +3033,11 @@ FE20..FE2F ; Mn # [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITL 11F36..11F3A ; Mn # [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R 11F40 ; Mn # KAWI VOWEL SIGN EU 11F42 ; Mn # KAWI CONJOINER +11F5A ; Mn # KAWI SIGN NUKTA 13440 ; Mn # EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13447..13455 ; Mn # [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +1611E..16129 ; Mn # [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612D..1612F ; Mn # [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA 16AF0..16AF4 ; Mn # [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; Mn # [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F4F ; Mn # MIAO SIGN CONSONANT MODIFIER BAR @@ -3003,11 +3067,12 @@ FE20..FE2F ; Mn # [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITL 1E2AE ; Mn # TOTO SIGN RISING TONE 1E2EC..1E2EF ; Mn # [4] WANCHO TONE TUP..WANCHO TONE KOINI 1E4EC..1E4EF ; Mn # [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH +1E5EE..1E5EF ; Mn # [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR 1E8D0..1E8D6 ; Mn # [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS 1E944..1E94A ; Mn # [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA E0100..E01EF ; Mn # [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 1985 +# Total code points: 2020 # ================================================ @@ -3159,6 +3224,12 @@ ABEC ; Mc # MEETEI MAYEK LUM IYEK 1134B..1134D ; Mc # [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA 11357 ; Mc # GRANTHA AU LENGTH MARK 11362..11363 ; Mc # [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +113B8..113BA ; Mc # [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II +113C2 ; Mc # TULU-TIGALARI VOWEL SIGN EE +113C5 ; Mc # TULU-TIGALARI VOWEL SIGN AI +113C7..113CA ; Mc # [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; Mc # [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA +113CF ; Mc # TULU-TIGALARI SIGN LOOPED VIRAMA 11435..11437 ; Mc # [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11440..11441 ; Mc # [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU 11445 ; Mc # NEWA SIGN VISARGA @@ -3175,6 +3246,7 @@ ABEC ; Mc # MEETEI MAYEK LUM IYEK 116AC ; Mc # TAKRI SIGN VISARGA 116AE..116AF ; Mc # [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II 116B6 ; Mc # TAKRI SIGN VIRAMA +1171E ; Mc # AHOM CONSONANT SIGN MEDIAL RA 11720..11721 ; Mc # [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11726 ; Mc # AHOM VOWEL SIGN E 1182C..1182E ; Mc # [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II @@ -3203,12 +3275,13 @@ ABEC ; Mc # MEETEI MAYEK LUM IYEK 11F34..11F35 ; Mc # [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA 11F3E..11F3F ; Mc # [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI 11F41 ; Mc # KAWI SIGN KILLER +1612A..1612C ; Mc # [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA 16F51..16F87 ; Mc # [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI 16FF0..16FF1 ; Mc # [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY 1D165..1D166 ; Mc # [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM 1D16D..1D172 ; Mc # [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 -# Total code points: 452 +# Total code points: 468 # ================================================ @@ -3253,6 +3326,7 @@ ABF0..ABF9 ; Nd # [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE FF10..FF19 ; Nd # [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE 104A0..104A9 ; Nd # [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE 10D30..10D39 ; Nd # [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +10D40..10D49 ; Nd # [10] GARAY DIGIT ZERO..GARAY DIGIT NINE 11066..1106F ; Nd # [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE 110F0..110F9 ; Nd # [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE 11136..1113F ; Nd # [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE @@ -3262,24 +3336,30 @@ FF10..FF19 ; Nd # [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE 114D0..114D9 ; Nd # [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE 11650..11659 ; Nd # [10] MODI DIGIT ZERO..MODI DIGIT NINE 116C0..116C9 ; Nd # [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE +116D0..116E3 ; Nd # [20] MYANMAR PAO DIGIT ZERO..MYANMAR EASTERN PWO KAREN DIGIT NINE 11730..11739 ; Nd # [10] AHOM DIGIT ZERO..AHOM DIGIT NINE 118E0..118E9 ; Nd # [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE 11950..11959 ; Nd # [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE +11BF0..11BF9 ; Nd # [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE 11C50..11C59 ; Nd # [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE 11D50..11D59 ; Nd # [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE 11DA0..11DA9 ; Nd # [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE 11F50..11F59 ; Nd # [10] KAWI DIGIT ZERO..KAWI DIGIT NINE +16130..16139 ; Nd # [10] GURUNG KHEMA DIGIT ZERO..GURUNG KHEMA DIGIT NINE 16A60..16A69 ; Nd # [10] MRO DIGIT ZERO..MRO DIGIT NINE 16AC0..16AC9 ; Nd # [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE 16B50..16B59 ; Nd # [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE +16D70..16D79 ; Nd # [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE +1CCF0..1CCF9 ; Nd # [10] OUTLINED DIGIT ZERO..OUTLINED DIGIT NINE 1D7CE..1D7FF ; Nd # [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE 1E140..1E149 ; Nd # [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE 1E2F0..1E2F9 ; Nd # [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE 1E4F0..1E4F9 ; Nd # [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE +1E5F1..1E5FA ; Nd # [10] OL ONAL DIGIT ZERO..OL ONAL DIGIT NINE 1E950..1E959 ; Nd # [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE 1FBF0..1FBF9 ; Nd # [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE -# Total code points: 680 +# Total code points: 760 # ================================================ @@ -3486,9 +3566,10 @@ FE31..FE32 ; Pd # [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FE58 ; Pd # SMALL EM DASH FE63 ; Pd # SMALL HYPHEN-MINUS FF0D ; Pd # FULLWIDTH HYPHEN-MINUS +10D6E ; Pd # GARAY HYPHEN 10EAD ; Pd # YEZIDI HYPHENATION MARK -# Total code points: 26 +# Total code points: 27 # ================================================ @@ -3735,8 +3816,9 @@ FF3F ; Pc # FULLWIDTH LOW LINE 1A1E..1A1F ; Po # [2] BUGINESE PALLAWA..BUGINESE END OF SECTION 1AA0..1AA6 ; Po # [7] TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA 1AA8..1AAD ; Po # [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG +1B4E..1B4F ; Po # [2] BALINESE INVERTED CARIK SIKI..BALINESE INVERTED CARIK PAREREN 1B5A..1B60 ; Po # [7] BALINESE PANTI..BALINESE PAMENENG -1B7D..1B7E ; Po # [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG +1B7D..1B7F ; Po # [3] BALINESE PANTI LANTANG..BALINESE PANTI BAWAK 1BFC..1BFF ; Po # [4] BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT 1C3B..1C3F ; Po # [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK 1C7E..1C7F ; Po # [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD @@ -3831,6 +3913,8 @@ FF64..FF65 ; Po # [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDL 111DD..111DF ; Po # [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2 11238..1123D ; Po # [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN 112A9 ; Po # MULTANI SECTION MARK +113D4..113D5 ; Po # [2] TULU-TIGALARI DANDA..TULU-TIGALARI DOUBLE DANDA +113D7..113D8 ; Po # [2] TULU-TIGALARI SIGN OM PUSHPIKA..TULU-TIGALARI SIGN SHRII PUSHPIKA 1144B..1144F ; Po # [5] NEWA DANDA..NEWA ABBREVIATION SIGN 1145A..1145B ; Po # [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK 1145D ; Po # NEWA INSERTION SIGN @@ -3847,6 +3931,7 @@ FF64..FF65 ; Po # [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDL 11A9A..11A9C ; Po # [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD 11A9E..11AA2 ; Po # [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2 11B00..11B09 ; Po # [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU +11BE1 ; Po # SUNUWAR SIGN PVO 11C41..11C45 ; Po # [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2 11C70..11C71 ; Po # [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD 11EF7..11EF8 ; Po # [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION @@ -3858,13 +3943,15 @@ FF64..FF65 ; Po # [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDL 16AF5 ; Po # BASSA VAH FULL STOP 16B37..16B3B ; Po # [5] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS FEEM 16B44 ; Po # PAHAWH HMONG SIGN XAUS +16D6D..16D6F ; Po # [3] KIRAT RAI SIGN YUPI..KIRAT RAI DOUBLE DANDA 16E97..16E9A ; Po # [4] MEDEFAIDRIN COMMA..MEDEFAIDRIN EXCLAMATION OH 16FE2 ; Po # OLD CHINESE HOOK MARK 1BC9F ; Po # DUPLOYAN PUNCTUATION CHINOOK FULL STOP 1DA87..1DA8B ; Po # [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS +1E5FF ; Po # OL ONAL ABBREVIATION SIGN 1E95E..1E95F ; Po # [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK -# Total code points: 628 +# Total code points: 640 # ================================================ @@ -3923,6 +4010,7 @@ FF5C ; Sm # FULLWIDTH VERTICAL LINE FF5E ; Sm # FULLWIDTH TILDE FFE2 ; Sm # FULLWIDTH NOT SIGN FFE9..FFEC ; Sm # [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW +10D8E..10D8F ; Sm # [2] GARAY PLUS SIGN..GARAY MINUS SIGN 1D6C1 ; Sm # MATHEMATICAL BOLD NABLA 1D6DB ; Sm # MATHEMATICAL BOLD PARTIAL DIFFERENTIAL 1D6FB ; Sm # MATHEMATICAL ITALIC NABLA @@ -3935,7 +4023,7 @@ FFE9..FFEC ; Sm # [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW 1D7C3 ; Sm # MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL 1EEF0..1EEF1 ; Sm # [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL -# Total code points: 948 +# Total code points: 950 # ================================================ @@ -4073,7 +4161,7 @@ FFE3 ; Sk # FULLWIDTH MACRON 232B..237B ; So # [81] ERASE TO THE LEFT..NOT CHECK MARK 237D..239A ; So # [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL 23B4..23DB ; So # [40] TOP SQUARE BRACKET..FUSE -23E2..2426 ; So # [69] WHITE TRAPEZIUM..SYMBOL FOR SUBSTITUTE FORM TWO +23E2..2429 ; So # [72] WHITE TRAPEZIUM..SYMBOL FOR DELETE MEDIUM SHADE FORM 2440..244A ; So # [11] OCR HOOK..OCR DOUBLE BACKSLASH 249C..24E9 ; So # [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z 2500..25B6 ; So # [183] BOX DRAWINGS LIGHT HORIZONTAL..BLACK RIGHT-POINTING TRIANGLE @@ -4101,7 +4189,7 @@ FFE3 ; Sk # FULLWIDTH MACRON 303E..303F ; So # [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE 3190..3191 ; So # [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK 3196..319F ; So # [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK -31C0..31E3 ; So # [36] CJK STROKE T..CJK STROKE Q +31C0..31E5 ; So # [38] CJK STROKE T..CJK STROKE SZP 31EF ; So # IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION 3200..321E ; So # [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU 322A..3247 ; So # [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO @@ -4136,6 +4224,8 @@ FFFC..FFFD ; So # [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTER 16B3C..16B3F ; So # [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB 16B45 ; So # PAHAWH HMONG SIGN CIM TSOV ROG 1BC9C ; So # DUPLOYAN SIGN O WITH CROSS +1CC00..1CCEF ; So # [240] UP-POINTING GO-KART..OUTLINED LATIN CAPITAL LETTER Z +1CD00..1CEB3 ; So # [436] BLOCK OCTANT-3..BLACK RIGHT TRIANGLE CARET 1CF50..1CFC3 ; So # [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK 1D000..1D0F5 ; So # [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO 1D100..1D126 ; So # [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2 @@ -4180,20 +4270,20 @@ FFFC..FFFD ; So # [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTER 1F850..1F859 ; So # [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW 1F860..1F887 ; So # [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW 1F890..1F8AD ; So # [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS -1F8B0..1F8B1 ; So # [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST +1F8B0..1F8BB ; So # [12] ARROW POINTING UPWARDS THEN NORTH WEST..SOUTH WEST ARROW FROM BAR +1F8C0..1F8C1 ; So # [2] LEFTWARDS ARROW FROM DOWNWARDS ARROW..RIGHTWARDS ARROW FROM DOWNWARDS ARROW 1F900..1FA53 ; So # [340] CIRCLED CROSS FORMEE WITH FOUR DOTS..BLACK CHESS KNIGHT-BISHOP 1FA60..1FA6D ; So # [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER 1FA70..1FA7C ; So # [13] BALLET SHOES..CRUTCH -1FA80..1FA88 ; So # [9] YO-YO..FLUTE -1FA90..1FABD ; So # [46] RINGED PLANET..WING -1FABF..1FAC5 ; So # [7] GOOSE..PERSON WITH CROWN -1FACE..1FADB ; So # [14] MOOSE..PEA POD -1FAE0..1FAE8 ; So # [9] MELTING FACE..SHAKING FACE +1FA80..1FA89 ; So # [10] YO-YO..HARP +1FA8F..1FAC6 ; So # [56] SHOVEL..FINGERPRINT +1FACE..1FADC ; So # [15] MOOSE..ROOT VEGETABLE +1FADF..1FAE9 ; So # [11] SPLATTER..FACE WITH BAGS UNDER EYES 1FAF0..1FAF8 ; So # [9] HAND WITH INDEX FINGER AND THUMB CROSSED..RIGHTWARDS PUSHING HAND 1FB00..1FB92 ; So # [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK -1FB94..1FBCA ; So # [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON +1FB94..1FBEF ; So # [92] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..TOP LEFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLE -# Total code points: 6639 +# Total code points: 7376 # ================================================ diff --git a/libcxx/utils/data/unicode/EastAsianWidth.txt b/libcxx/utils/data/unicode/EastAsianWidth.txt index 02df4df475cbee..99f7a31ea5d8a2 100644 --- a/libcxx/utils/data/unicode/EastAsianWidth.txt +++ b/libcxx/utils/data/unicode/EastAsianWidth.txt @@ -1,8 +1,8 @@ -# EastAsianWidth-15.1.0.txt -# Date: 2023-07-28, 23:34:08 GMT -# © 2023 Unicode®, Inc. +# EastAsianWidth-16.0.0.txt +# Date: 2024-04-30, 21:48:20 GMT +# © 2024 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database # For documentation, see https://www.unicode.org/reports/tr44/ @@ -334,7 +334,7 @@ 0888 ; N # Sk ARABIC RAISED ROUND DOT 0889..088E ; N # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL 0890..0891 ; N # Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE -0898..089F ; N # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; N # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08A0..08C8 ; N # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; N # Lm ARABIC SMALL FARSI YEH 08CA..08E1 ; N # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA @@ -819,12 +819,13 @@ 1B42 ; N # Mn BALINESE VOWEL SIGN PEPET 1B43..1B44 ; N # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG 1B45..1B4C ; N # Lo [8] BALINESE LETTER KAF SASAK..BALINESE LETTER ARCHAIC JNYA +1B4E..1B4F ; N # Po [2] BALINESE INVERTED CARIK SIKI..BALINESE INVERTED CARIK PAREREN 1B50..1B59 ; N # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE 1B5A..1B60 ; N # Po [7] BALINESE PANTI..BALINESE PAMENENG 1B61..1B6A ; N # So [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE 1B6B..1B73 ; N # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG 1B74..1B7C ; N # So [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING -1B7D..1B7E ; N # Po [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG +1B7D..1B7F ; N # Po [3] BALINESE PANTI LANTANG..BALINESE PANTI BAWAK 1B80..1B81 ; N # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR 1B82 ; N # Mc SUNDANESE SIGN PANGWISAD 1B83..1BA0 ; N # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA @@ -859,7 +860,7 @@ 1C5A..1C77 ; N # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; N # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD 1C7E..1C7F ; N # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD -1C80..1C88 ; N # Ll [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C80..1C8A ; N # L& [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE 1C90..1CBA ; N # Lu [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN 1CBD..1CBF ; N # Lu [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN 1CC0..1CC7 ; N # Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA @@ -1142,7 +1143,7 @@ 23F1..23F2 ; N # So [2] STOPWATCH..TIMER CLOCK 23F3 ; W # So HOURGLASS WITH FLOWING SAND 23F4..23FF ; N # So [12] BLACK MEDIUM LEFT-POINTING TRIANGLE..OBSERVER EYE SYMBOL -2400..2426 ; N # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO +2400..2429 ; N # So [42] SYMBOL FOR NULL..SYMBOL FOR DELETE MEDIUM SHADE FORM 2440..244A ; N # So [11] OCR HOOK..OCR DOUBLE BACKSLASH 2460..249B ; A # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP 249C..24E9 ; A # So [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z @@ -1195,7 +1196,9 @@ 261C ; A # So WHITE LEFT POINTING INDEX 261D ; N # So WHITE UP POINTING INDEX 261E ; A # So WHITE RIGHT POINTING INDEX -261F..263F ; N # So [33] WHITE DOWN POINTING INDEX..MERCURY +261F..262F ; N # So [17] WHITE DOWN POINTING INDEX..YIN YANG +2630..2637 ; W # So [8] TRIGRAM FOR HEAVEN..TRIGRAM FOR EARTH +2638..263F ; N # So [8] WHEEL OF DHARMA..MERCURY 2640 ; A # So FEMALE SIGN 2641 ; N # So EARTH 2642 ; A # So MALE SIGN @@ -1213,7 +1216,9 @@ 266F ; A # Sm MUSIC SHARP SIGN 2670..267E ; N # So [15] WEST SYRIAC CROSS..PERMANENT PAPER SIGN 267F ; W # So WHEELCHAIR SYMBOL -2680..2692 ; N # So [19] DIE FACE-1..HAMMER AND PICK +2680..2689 ; N # So [10] DIE FACE-1..BLACK CIRCLE WITH TWO WHITE DOTS +268A..268F ; W # So [6] MONOGRAM FOR YANG..DIGRAM FOR GREATER YIN +2690..2692 ; N # So [3] WHITE FLAG..HAMMER AND PICK 2693 ; W # So ANCHOR 2694..269D ; N # So [10] CROSSED SWORDS..OUTLINED WHITE STAR 269E..269F ; A # So [2] THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT @@ -1487,7 +1492,7 @@ 3192..3195 ; W # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK 3196..319F ; W # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK 31A0..31BF ; W # Lo [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH -31C0..31E3 ; W # So [36] CJK STROKE T..CJK STROKE Q +31C0..31E5 ; W # So [38] CJK STROKE T..CJK STROKE SZP 31EF ; W # So IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION 31F0..31FF ; W # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO 3200..321E ; W # So [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU @@ -1503,7 +1508,7 @@ 32C0..32FF ; W # So [64] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..SQUARE ERA NAME REIWA 3300..33FF ; W # So [256] SQUARE APAATO..SQUARE GAL 3400..4DBF ; W # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF -4DC0..4DFF ; N # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION +4DC0..4DFF ; W # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION 4E00..9FFF ; W # Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF A000..A014 ; W # Lo [21] YI SYLLABLE IT..YI SYLLABLE E A015 ; W # Lm YI SYLLABLE WU @@ -1543,10 +1548,10 @@ A788 ; N # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A789..A78A ; N # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN A78B..A78E ; N # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; N # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; N # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A790..A7CD ; N # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE A7D0..A7D1 ; N # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; N # Ll LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; N # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7D5..A7DC ; N # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F2..A7F4 ; N # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; N # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; N # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I @@ -1870,6 +1875,7 @@ FFFD ; A # So REPLACEMENT CHARACTER 105A3..105B1 ; N # Ll [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE 105B3..105B9 ; N # Ll [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE 105BB..105BC ; N # Ll [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +105C0..105F3 ; N # Lo [52] TODHRI LETTER A..TODHRI LETTER OO 10600..10736 ; N # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 10740..10755 ; N # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE 10760..10767 ; N # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 @@ -1942,12 +1948,23 @@ FFFD ; A # So REPLACEMENT CHARACTER 10D00..10D23 ; N # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA 10D24..10D27 ; N # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI 10D30..10D39 ; N # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +10D40..10D49 ; N # Nd [10] GARAY DIGIT ZERO..GARAY DIGIT NINE +10D4A..10D4D ; N # Lo [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE +10D4E ; N # Lm GARAY VOWEL LENGTH MARK +10D4F ; N # Lo GARAY SUKUN +10D50..10D65 ; N # Lu [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA +10D69..10D6D ; N # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK +10D6E ; N # Pd GARAY HYPHEN +10D6F ; N # Lm GARAY REDUPLICATION MARK +10D70..10D85 ; N # Ll [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA +10D8E..10D8F ; N # Sm [2] GARAY PLUS SIGN..GARAY MINUS SIGN 10E60..10E7E ; N # No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS 10E80..10EA9 ; N # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EAB..10EAC ; N # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK 10EAD ; N # Pd YEZIDI HYPHENATION MARK 10EB0..10EB1 ; N # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE -10EFD..10EFF ; N # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EC2..10EC4 ; N # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW +10EFC..10EFF ; N # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F00..10F1C ; N # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F1D..10F26 ; N # No [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF 10F27 ; N # Lo OLD SOGDIAN LIGATURE AYIN-DALETH @@ -2064,6 +2081,26 @@ FFFD ; A # So REPLACEMENT CHARACTER 11362..11363 ; N # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C ; N # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; N # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11380..11389 ; N # Lo [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL +1138B ; N # Lo TULU-TIGALARI LETTER EE +1138E ; N # Lo TULU-TIGALARI LETTER AI +11390..113B5 ; N # Lo [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA +113B7 ; N # Lo TULU-TIGALARI SIGN AVAGRAHA +113B8..113BA ; N # Mc [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II +113BB..113C0 ; N # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113C2 ; N # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; N # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113CA ; N # Mc [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; N # Mc [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA +113CE ; N # Mn TULU-TIGALARI SIGN VIRAMA +113CF ; N # Mc TULU-TIGALARI SIGN LOOPED VIRAMA +113D0 ; N # Mn TULU-TIGALARI CONJOINER +113D1 ; N # Lo TULU-TIGALARI REPHA +113D2 ; N # Mn TULU-TIGALARI GEMINATION MARK +113D3 ; N # Lo TULU-TIGALARI SIGN PLUTA +113D4..113D5 ; N # Po [2] TULU-TIGALARI DANDA..TULU-TIGALARI DOUBLE DANDA +113D7..113D8 ; N # Po [2] TULU-TIGALARI SIGN OM PUSHPIKA..TULU-TIGALARI SIGN SHRII PUSHPIKA +113E1..113E2 ; N # Mn [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11400..11434 ; N # Lo [53] NEWA LETTER A..NEWA LETTER HA 11435..11437 ; N # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11438..1143F ; N # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI @@ -2123,8 +2160,11 @@ FFFD ; A # So REPLACEMENT CHARACTER 116B8 ; N # Lo TAKRI LETTER ARCHAIC KHA 116B9 ; N # Po TAKRI ABBREVIATION SIGN 116C0..116C9 ; N # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE +116D0..116E3 ; N # Nd [20] MYANMAR PAO DIGIT ZERO..MYANMAR EASTERN PWO KAREN DIGIT NINE 11700..1171A ; N # Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA -1171D..1171F ; N # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; N # Mn AHOM CONSONANT SIGN MEDIAL LA +1171E ; N # Mc AHOM CONSONANT SIGN MEDIAL RA +1171F ; N # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11720..11721 ; N # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11722..11725 ; N # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11726 ; N # Mc AHOM VOWEL SIGN E @@ -2195,6 +2235,9 @@ FFFD ; A # So REPLACEMENT CHARACTER 11AB0..11ABF ; N # Lo [16] CANADIAN SYLLABICS NATTILIK HI..CANADIAN SYLLABICS SPA 11AC0..11AF8 ; N # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL 11B00..11B09 ; N # Po [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU +11BC0..11BE0 ; N # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO +11BE1 ; N # Po SUNUWAR SIGN PVO +11BF0..11BF9 ; N # Nd [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE 11C00..11C08 ; N # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; N # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA 11C2F ; N # Mc BHAIKSUKI VOWEL SIGN AA @@ -2253,6 +2296,7 @@ FFFD ; A # So REPLACEMENT CHARACTER 11F42 ; N # Mn KAWI CONJOINER 11F43..11F4F ; N # Po [13] KAWI DANDA..KAWI PUNCTUATION CLOSING SPIRAL 11F50..11F59 ; N # Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE +11F5A ; N # Mn KAWI SIGN NUKTA 11FB0 ; N # Lo LISU LETTER YHA 11FC0..11FD4 ; N # No [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH 11FD5..11FDC ; N # So [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI @@ -2270,7 +2314,13 @@ FFFD ; A # So REPLACEMENT CHARACTER 13440 ; N # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13441..13446 ; N # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN 13447..13455 ; N # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +13460..143FA ; N # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA 14400..14646 ; N # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16100..1611D ; N # Lo [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA +1611E..16129 ; N # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612A..1612C ; N # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA +1612D..1612F ; N # Mn [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA +16130..16139 ; N # Nd [10] GURUNG KHEMA DIGIT ZERO..GURUNG KHEMA DIGIT NINE 16800..16A38 ; N # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ 16A40..16A5E ; N # Lo [31] MRO LETTER TA..MRO LETTER TEK 16A60..16A69 ; N # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE @@ -2291,6 +2341,11 @@ FFFD ; A # So REPLACEMENT CHARACTER 16B5B..16B61 ; N # No [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS 16B63..16B77 ; N # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS 16B7D..16B8F ; N # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16D40..16D42 ; N # Lm [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA +16D43..16D6A ; N # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU +16D6B..16D6C ; N # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT +16D6D..16D6F ; N # Po [3] KIRAT RAI SIGN YUPI..KIRAT RAI DOUBLE DANDA +16D70..16D79 ; N # Nd [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE 16E40..16E7F ; N # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y 16E80..16E96 ; N # No [23] MEDEFAIDRIN DIGIT ZERO..MEDEFAIDRIN DIGIT THREE ALTERNATE FORM 16E97..16E9A ; N # Po [4] MEDEFAIDRIN COMMA..MEDEFAIDRIN EXCLAMATION OH @@ -2308,6 +2363,7 @@ FFFD ; A # So REPLACEMENT CHARACTER 17000..187F7 ; W # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 18800..18AFF ; W # Lo [768] TANGUT COMPONENT-001..TANGUT COMPONENT-768 18B00..18CD5 ; W # Lo [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5 +18CFF ; W # Lo KHITAN SMALL SCRIPT CHARACTER-18CFF 18D00..18D08 ; W # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 1AFF0..1AFF3 ; W # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; W # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 @@ -2327,6 +2383,9 @@ FFFD ; A # So REPLACEMENT CHARACTER 1BC9D..1BC9E ; N # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK 1BC9F ; N # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP 1BCA0..1BCA3 ; N # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP +1CC00..1CCEF ; N # So [240] UP-POINTING GO-KART..OUTLINED LATIN CAPITAL LETTER Z +1CCF0..1CCF9 ; N # Nd [10] OUTLINED DIGIT ZERO..OUTLINED DIGIT NINE +1CD00..1CEB3 ; N # So [436] BLOCK OCTANT-3..BLACK RIGHT TRIANGLE CARET 1CF00..1CF2D ; N # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT 1CF30..1CF46 ; N # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG 1CF50..1CFC3 ; N # So [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK @@ -2349,8 +2408,9 @@ FFFD ; A # So REPLACEMENT CHARACTER 1D245 ; N # So GREEK MUSICAL LEIMMA 1D2C0..1D2D3 ; N # No [20] KAKTOVIK NUMERAL ZERO..KAKTOVIK NUMERAL NINETEEN 1D2E0..1D2F3 ; N # No [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN -1D300..1D356 ; N # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING -1D360..1D378 ; N # No [25] COUNTING ROD UNIT DIGIT ONE..TALLY MARK FIVE +1D300..1D356 ; W # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING +1D360..1D376 ; W # No [23] COUNTING ROD UNIT DIGIT ONE..IDEOGRAPHIC TALLY MARK FIVE +1D377..1D378 ; N # No [2] TALLY MARK ONE..TALLY MARK FIVE 1D400..1D454 ; N # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G 1D456..1D49C ; N # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A 1D49E..1D49F ; N # Lu [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D @@ -2431,6 +2491,11 @@ FFFD ; A # So REPLACEMENT CHARACTER 1E4EB ; N # Lm NAG MUNDARI SIGN OJOD 1E4EC..1E4EF ; N # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH 1E4F0..1E4F9 ; N # Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE +1E5D0..1E5ED ; N # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG +1E5EE..1E5EF ; N # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR +1E5F0 ; N # Lo OL ONAL SIGN HODDOND +1E5F1..1E5FA ; N # Nd [10] OL ONAL DIGIT ZERO..OL ONAL DIGIT NINE +1E5FF ; N # Po OL ONAL ABBREVIATION SIGN 1E7E0..1E7E6 ; N # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; N # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; N # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -2574,7 +2639,8 @@ FFFD ; A # So REPLACEMENT CHARACTER 1F850..1F859 ; N # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW 1F860..1F887 ; N # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW 1F890..1F8AD ; N # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS -1F8B0..1F8B1 ; N # So [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST +1F8B0..1F8BB ; N # So [12] ARROW POINTING UPWARDS THEN NORTH WEST..SOUTH WEST ARROW FROM BAR +1F8C0..1F8C1 ; N # So [2] LEFTWARDS ARROW FROM DOWNWARDS ARROW..RIGHTWARDS ARROW FROM DOWNWARDS ARROW 1F900..1F90B ; N # So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT 1F90C..1F93A ; W # So [47] PINCHED FINGERS..FENCER 1F93B ; N # So MODERN PENTATHLON @@ -2584,14 +2650,13 @@ FFFD ; A # So REPLACEMENT CHARACTER 1FA00..1FA53 ; N # So [84] NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP 1FA60..1FA6D ; N # So [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER 1FA70..1FA7C ; W # So [13] BALLET SHOES..CRUTCH -1FA80..1FA88 ; W # So [9] YO-YO..FLUTE -1FA90..1FABD ; W # So [46] RINGED PLANET..WING -1FABF..1FAC5 ; W # So [7] GOOSE..PERSON WITH CROWN -1FACE..1FADB ; W # So [14] MOOSE..PEA POD -1FAE0..1FAE8 ; W # So [9] MELTING FACE..SHAKING FACE +1FA80..1FA89 ; W # So [10] YO-YO..HARP +1FA8F..1FAC6 ; W # So [56] SHOVEL..FINGERPRINT +1FACE..1FADC ; W # So [15] MOOSE..ROOT VEGETABLE +1FADF..1FAE9 ; W # So [11] SPLATTER..FACE WITH BAGS UNDER EYES 1FAF0..1FAF8 ; W # So [9] HAND WITH INDEX FINGER AND THUMB CROSSED..RIGHTWARDS PUSHING HAND 1FB00..1FB92 ; N # So [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK -1FB94..1FBCA ; N # So [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON +1FB94..1FBEF ; N # So [92] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..TOP LEFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLE 1FBF0..1FBF9 ; N # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE 20000..2A6DF ; W # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF 2A6E0..2A6FF ; W # Cn [32] .. diff --git a/libcxx/utils/data/unicode/GraphemeBreakProperty.txt b/libcxx/utils/data/unicode/GraphemeBreakProperty.txt index 12453cbdb54a15..a863397ddabafe 100644 --- a/libcxx/utils/data/unicode/GraphemeBreakProperty.txt +++ b/libcxx/utils/data/unicode/GraphemeBreakProperty.txt @@ -1,8 +1,8 @@ -# GraphemeBreakProperty-15.1.0.txt -# Date: 2023-01-05, 20:34:41 GMT -# © 2023 Unicode®, Inc. +# GraphemeBreakProperty-16.0.0.txt +# Date: 2024-05-31, 18:09:38 GMT +# © 2024 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database # For documentation, see https://www.unicode.org/reports/tr44/ @@ -27,6 +27,7 @@ 110BD ; Prepend # Cf KAITHI NUMBER SIGN 110CD ; Prepend # Cf KAITHI NUMBER SIGN ABOVE 111C2..111C3 ; Prepend # Lo [2] SHARADA SIGN JIHVAMULIYA..SHARADA SIGN UPADHMANIYA +113D1 ; Prepend # Lo TULU-TIGALARI REPHA 1193F ; Prepend # Lo DIVES AKURU PREFIXED NASAL SIGN 11941 ; Prepend # Lo DIVES AKURU INITIAL RA 11A3A ; Prepend # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA @@ -34,7 +35,7 @@ 11D46 ; Prepend # Lo MASARAM GONDI REPHA 11F02 ; Prepend # Lo KAWI SIGN REPHA -# Total code points: 27 +# Total code points: 28 # ================================================ @@ -106,7 +107,7 @@ E01F0..E0FFF ; Control # Cn [3600] .. 0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA 0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK -0898..089F ; Extend # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +0897..089F ; Extend # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08CA..08E1 ; Extend # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA 08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA 093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE @@ -163,8 +164,11 @@ E01F0..E0FFF ; Control # Cn [3600] .. 0C81 ; Extend # Mn KANNADA SIGN CANDRABINDU 0CBC ; Extend # Mn KANNADA SIGN NUKTA 0CBF ; Extend # Mn KANNADA VOWEL SIGN I +0CC0 ; Extend # Mc KANNADA VOWEL SIGN II 0CC2 ; Extend # Mc KANNADA VOWEL SIGN UU 0CC6 ; Extend # Mn KANNADA VOWEL SIGN E +0CC7..0CC8 ; Extend # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI +0CCA..0CCB ; Extend # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO 0CCC..0CCD ; Extend # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA 0CD5..0CD6 ; Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK 0CE2..0CE3 ; Extend # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL @@ -210,7 +214,9 @@ E01F0..E0FFF ; Control # Cn [3600] .. 109D ; Extend # Mn MYANMAR VOWEL SIGN AITON AI 135D..135F ; Extend # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK 1712..1714 ; Extend # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA +1715 ; Extend # Mc TAGALOG SIGN PAMUDPOD 1732..1733 ; Extend # Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U +1734 ; Extend # Mc HANUNOO SIGN PAMUDPOD 1752..1753 ; Extend # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U 1772..1773 ; Extend # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U 17B4..17B5 ; Extend # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA @@ -242,17 +248,22 @@ E01F0..E0FFF ; Control # Cn [3600] .. 1B34 ; Extend # Mn BALINESE SIGN REREKAN 1B35 ; Extend # Mc BALINESE VOWEL SIGN TEDUNG 1B36..1B3A ; Extend # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA +1B3B ; Extend # Mc BALINESE VOWEL SIGN RA REPA TEDUNG 1B3C ; Extend # Mn BALINESE VOWEL SIGN LA LENGA +1B3D ; Extend # Mc BALINESE VOWEL SIGN LA LENGA TEDUNG 1B42 ; Extend # Mn BALINESE VOWEL SIGN PEPET +1B43..1B44 ; Extend # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG 1B6B..1B73 ; Extend # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG 1B80..1B81 ; Extend # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR 1BA2..1BA5 ; Extend # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU 1BA8..1BA9 ; Extend # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG +1BAA ; Extend # Mc SUNDANESE SIGN PAMAAEH 1BAB..1BAD ; Extend # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA 1BE6 ; Extend # Mn BATAK SIGN TOMPI 1BE8..1BE9 ; Extend # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE 1BED ; Extend # Mn BATAK VOWEL SIGN KARO O 1BEF..1BF1 ; Extend # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H +1BF2..1BF3 ; Extend # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN 1C2C..1C33 ; Extend # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T 1C36..1C37 ; Extend # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA 1CD0..1CD2 ; Extend # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA @@ -289,10 +300,12 @@ A8E0..A8F1 ; Extend # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEV A8FF ; Extend # Mn DEVANAGARI VOWEL SIGN AY A926..A92D ; Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU A947..A951 ; Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R +A953 ; Extend # Mc REJANG VIRAMA A980..A982 ; Extend # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR A9B3 ; Extend # Mn JAVANESE SIGN CECAK TELU A9B6..A9B9 ; Extend # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT A9BC..A9BD ; Extend # Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET +A9C0 ; Extend # Mc JAVANESE PANGKON A9E5 ; Extend # Mn MYANMAR SIGN SHAN SAW AA29..AA2E ; Extend # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE AA31..AA32 ; Extend # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE @@ -324,8 +337,9 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 10A3F ; Extend # Mn KHAROSHTHI VIRAMA 10AE5..10AE6 ; Extend # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW 10D24..10D27 ; Extend # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D69..10D6D ; Extend # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK 10EAB..10EAC ; Extend # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK -10EFD..10EFF ; Extend # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10EFC..10EFF ; Extend # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA 10F46..10F50 ; Extend # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW 10F82..10F85 ; Extend # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW 11001 ; Extend # Mn BRAHMI SIGN ANUSVARA @@ -342,10 +356,12 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11173 ; Extend # Mn MAHAJANI SIGN NUKTA 11180..11181 ; Extend # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA 111B6..111BE ; Extend # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O +111C0 ; Extend # Mc SHARADA SIGN VIRAMA 111C9..111CC ; Extend # Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK 111CF ; Extend # Mn SHARADA SIGN INVERTED CANDRABINDU 1122F..11231 ; Extend # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI 11234 ; Extend # Mn KHOJKI SIGN ANUSVARA +11235 ; Extend # Mc KHOJKI SIGN VIRAMA 11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA 1123E ; Extend # Mn KHOJKI SIGN SUKUN 11241 ; Extend # Mn KHOJKI VOWEL SIGN VOCALIC R @@ -355,9 +371,20 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 1133B..1133C ; Extend # Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA 1133E ; Extend # Mc GRANTHA VOWEL SIGN AA 11340 ; Extend # Mn GRANTHA VOWEL SIGN II +1134D ; Extend # Mc GRANTHA SIGN VIRAMA 11357 ; Extend # Mc GRANTHA AU LENGTH MARK 11366..1136C ; Extend # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; Extend # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +113B8 ; Extend # Mc TULU-TIGALARI VOWEL SIGN AA +113BB..113C0 ; Extend # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113C2 ; Extend # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; Extend # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113C9 ; Extend # Mc [3] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI AU LENGTH MARK +113CE ; Extend # Mn TULU-TIGALARI SIGN VIRAMA +113CF ; Extend # Mc TULU-TIGALARI SIGN LOOPED VIRAMA +113D0 ; Extend # Mn TULU-TIGALARI CONJOINER +113D2 ; Extend # Mn TULU-TIGALARI GEMINATION MARK +113E1..113E2 ; Extend # Mn [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA 11438..1143F ; Extend # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI 11442..11444 ; Extend # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA 11446 ; Extend # Mn NEWA SIGN NUKTA @@ -379,14 +406,17 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 116AB ; Extend # Mn TAKRI SIGN ANUSVARA 116AD ; Extend # Mn TAKRI VOWEL SIGN AA 116B0..116B5 ; Extend # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU +116B6 ; Extend # Mc TAKRI SIGN VIRAMA 116B7 ; Extend # Mn TAKRI SIGN NUKTA -1171D..1171F ; Extend # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +1171D ; Extend # Mn AHOM CONSONANT SIGN MEDIAL LA +1171F ; Extend # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA 11722..11725 ; Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11727..1172B ; Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER 1182F..11837 ; Extend # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA 11839..1183A ; Extend # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA 11930 ; Extend # Mc DIVES AKURU VOWEL SIGN AA 1193B..1193C ; Extend # Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU +1193D ; Extend # Mc DIVES AKURU SIGN HALANTA 1193E ; Extend # Mn DIVES AKURU VIRAMA 11943 ; Extend # Mn DIVES AKURU SIGN NUKTA 119D4..119D7 ; Extend # Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR @@ -419,20 +449,25 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11F00..11F01 ; Extend # Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA 11F36..11F3A ; Extend # Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R 11F40 ; Extend # Mn KAWI VOWEL SIGN EU +11F41 ; Extend # Mc KAWI SIGN KILLER 11F42 ; Extend # Mn KAWI CONJOINER +11F5A ; Extend # Mn KAWI SIGN NUKTA 13440 ; Extend # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY 13447..13455 ; Extend # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +1611E..16129 ; Extend # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612D..1612F ; Extend # Mn [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA 16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F4F ; Extend # Mn MIAO SIGN CONSONANT MODIFIER BAR 16F8F..16F92 ; Extend # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16FE4 ; Extend # Mn KHITAN SMALL SCRIPT FILLER +16FF0..16FF1 ; Extend # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY 1BC9D..1BC9E ; Extend # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK 1CF00..1CF2D ; Extend # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT 1CF30..1CF46 ; Extend # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG -1D165 ; Extend # Mc MUSICAL SYMBOL COMBINING STEM +1D165..1D166 ; Extend # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM 1D167..1D169 ; Extend # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 -1D16E..1D172 ; Extend # Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5 +1D16D..1D172 ; Extend # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 1D17B..1D182 ; Extend # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE 1D185..1D18B ; Extend # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE 1D1AA..1D1AD ; Extend # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO @@ -453,13 +488,14 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 1E2AE ; Extend # Mn TOTO SIGN RISING TONE 1E2EC..1E2EF ; Extend # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI 1E4EC..1E4EF ; Extend # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH +1E5EE..1E5EF ; Extend # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR 1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS 1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA 1F3FB..1F3FF ; Extend # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 2130 +# Total code points: 2198 # ================================================ @@ -496,10 +532,8 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 0C41..0C44 ; SpacingMark # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR 0C82..0C83 ; SpacingMark # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 0CBE ; SpacingMark # Mc KANNADA VOWEL SIGN AA -0CC0..0CC1 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN U +0CC1 ; SpacingMark # Mc KANNADA VOWEL SIGN U 0CC3..0CC4 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN VOCALIC R..KANNADA VOWEL SIGN VOCALIC RR -0CC7..0CC8 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI -0CCA..0CCB ; SpacingMark # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO 0CF3 ; SpacingMark # Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT 0D02..0D03 ; SpacingMark # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D3F..0D40 ; SpacingMark # Mc [2] MALAYALAM VOWEL SIGN I..MALAYALAM VOWEL SIGN II @@ -517,8 +551,6 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 103B..103C ; SpacingMark # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA 1056..1057 ; SpacingMark # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR 1084 ; SpacingMark # Mc MYANMAR VOWEL SIGN SHAN E -1715 ; SpacingMark # Mc TAGALOG SIGN PAMUDPOD -1734 ; SpacingMark # Mc HANUNOO SIGN PAMUDPOD 17B6 ; SpacingMark # Mc KHMER VOWEL SIGN AA 17BE..17C5 ; SpacingMark # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU 17C7..17C8 ; SpacingMark # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU @@ -531,17 +563,13 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 1A57 ; SpacingMark # Mc TAI THAM CONSONANT SIGN LA TANG LAI 1A6D..1A72 ; SpacingMark # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI 1B04 ; SpacingMark # Mc BALINESE SIGN BISAH -1B3B ; SpacingMark # Mc BALINESE VOWEL SIGN RA REPA TEDUNG -1B3D..1B41 ; SpacingMark # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG -1B43..1B44 ; SpacingMark # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG +1B3E..1B41 ; SpacingMark # Mc [4] BALINESE VOWEL SIGN TALING..BALINESE VOWEL SIGN TALING REPA TEDUNG 1B82 ; SpacingMark # Mc SUNDANESE SIGN PANGWISAD 1BA1 ; SpacingMark # Mc SUNDANESE CONSONANT SIGN PAMINGKAL 1BA6..1BA7 ; SpacingMark # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG -1BAA ; SpacingMark # Mc SUNDANESE SIGN PAMAAEH 1BE7 ; SpacingMark # Mc BATAK VOWEL SIGN E 1BEA..1BEC ; SpacingMark # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O 1BEE ; SpacingMark # Mc BATAK VOWEL SIGN U -1BF2..1BF3 ; SpacingMark # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN 1C24..1C2B ; SpacingMark # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU 1C34..1C35 ; SpacingMark # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG 1CE1 ; SpacingMark # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA @@ -550,11 +578,11 @@ A823..A824 ; SpacingMark # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI V A827 ; SpacingMark # Mc SYLOTI NAGRI VOWEL SIGN OO A880..A881 ; SpacingMark # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA A8B4..A8C3 ; SpacingMark # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU -A952..A953 ; SpacingMark # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA +A952 ; SpacingMark # Mc REJANG CONSONANT SIGN H A983 ; SpacingMark # Mc JAVANESE SIGN WIGNYAN A9B4..A9B5 ; SpacingMark # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG A9BA..A9BB ; SpacingMark # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE -A9BE..A9C0 ; SpacingMark # Mc [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON +A9BE..A9BF ; SpacingMark # Mc [2] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE CONSONANT SIGN CAKRA AA2F..AA30 ; SpacingMark # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI AA33..AA34 ; SpacingMark # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA AA4D ; SpacingMark # Mc CHAM CONSONANT SIGN FINAL H @@ -574,18 +602,20 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 11145..11146 ; SpacingMark # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI 11182 ; SpacingMark # Mc SHARADA SIGN VISARGA 111B3..111B5 ; SpacingMark # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II -111BF..111C0 ; SpacingMark # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA +111BF ; SpacingMark # Mc SHARADA VOWEL SIGN AU 111CE ; SpacingMark # Mc SHARADA VOWEL SIGN PRISHTHAMATRA E 1122C..1122E ; SpacingMark # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II 11232..11233 ; SpacingMark # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU -11235 ; SpacingMark # Mc KHOJKI SIGN VIRAMA 112E0..112E2 ; SpacingMark # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II 11302..11303 ; SpacingMark # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA 1133F ; SpacingMark # Mc GRANTHA VOWEL SIGN I 11341..11344 ; SpacingMark # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR 11347..11348 ; SpacingMark # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI -1134B..1134D ; SpacingMark # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA +1134B..1134C ; SpacingMark # Mc [2] GRANTHA VOWEL SIGN OO..GRANTHA VOWEL SIGN AU 11362..11363 ; SpacingMark # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +113B9..113BA ; SpacingMark # Mc [2] TULU-TIGALARI VOWEL SIGN I..TULU-TIGALARI VOWEL SIGN II +113CA ; SpacingMark # Mc TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; SpacingMark # Mc [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA 11435..11437 ; SpacingMark # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 11440..11441 ; SpacingMark # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU 11445 ; SpacingMark # Mc NEWA SIGN VISARGA @@ -602,13 +632,12 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 1163E ; SpacingMark # Mc MODI SIGN VISARGA 116AC ; SpacingMark # Mc TAKRI SIGN VISARGA 116AE..116AF ; SpacingMark # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II -116B6 ; SpacingMark # Mc TAKRI SIGN VIRAMA +1171E ; SpacingMark # Mc AHOM CONSONANT SIGN MEDIAL RA 11726 ; SpacingMark # Mc AHOM VOWEL SIGN E 1182C..1182E ; SpacingMark # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II 11838 ; SpacingMark # Mc DOGRA SIGN VISARGA 11931..11935 ; SpacingMark # Mc [5] DIVES AKURU VOWEL SIGN I..DIVES AKURU VOWEL SIGN E 11937..11938 ; SpacingMark # Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O -1193D ; SpacingMark # Mc DIVES AKURU SIGN HALANTA 11940 ; SpacingMark # Mc DIVES AKURU MEDIAL YA 11942 ; SpacingMark # Mc DIVES AKURU MEDIAL RA 119D1..119D3 ; SpacingMark # Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II @@ -629,13 +658,10 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 11F03 ; SpacingMark # Mc KAWI SIGN VISARGA 11F34..11F35 ; SpacingMark # Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA 11F3E..11F3F ; SpacingMark # Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI -11F41 ; SpacingMark # Mc KAWI SIGN KILLER +1612A..1612C ; SpacingMark # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA 16F51..16F87 ; SpacingMark # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI -16FF0..16FF1 ; SpacingMark # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY -1D166 ; SpacingMark # Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM -1D16D ; SpacingMark # Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT -# Total code points: 395 +# Total code points: 378 # ================================================ @@ -648,8 +674,10 @@ A960..A97C ; L # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANG 1160..11A7 ; V # Lo [72] HANGUL JUNGSEONG FILLER..HANGUL JUNGSEONG O-YAE D7B0..D7C6 ; V # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E +16D63 ; V # Lo KIRAT RAI VOWEL SIGN AA +16D67..16D6A ; V # Lo [4] KIRAT RAI VOWEL SIGN E..KIRAT RAI VOWEL SIGN AU -# Total code points: 95 +# Total code points: 100 # ================================================ diff --git a/libcxx/utils/data/unicode/GraphemeBreakTest.txt b/libcxx/utils/data/unicode/GraphemeBreakTest.txt index 4c1ed512e4510d..d10c174b6896d3 100644 --- a/libcxx/utils/data/unicode/GraphemeBreakTest.txt +++ b/libcxx/utils/data/unicode/GraphemeBreakTest.txt @@ -1,8 +1,8 @@ -# GraphemeBreakTest-15.1.0.txt -# Date: 2023-08-07, 15:52:55 GMT -# © 2023 Unicode®, Inc. +# GraphemeBreakTest-16.0.0.txt +# Date: 2024-05-02, 15:02:48 GMT +# © 2024 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database # For documentation, see https://www.unicode.org/reports/tr44/ @@ -30,8 +30,8 @@ ÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0020 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (Control) ÷ [0.3] ÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0020 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0020 × 0308 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0020 × 200C ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0020 × 0308 × 200C ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0020 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -48,8 +48,6 @@ ÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0020 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0020 × 0900 ÷ # ÷ [0.2] SPACE (Other) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0020 × 0308 × 0900 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0020 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0020 ÷ 0904 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -62,8 +60,8 @@ ÷ 0020 × 0308 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0020 × 093C ÷ # ÷ [0.2] SPACE (Other) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0020 × 0308 × 093C ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0020 × 0900 ÷ # ÷ [0.2] SPACE (Other) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0020 × 0308 × 0900 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0020 × 094D ÷ # ÷ [0.2] SPACE (Other) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0020 × 0308 × 094D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -78,8 +76,8 @@ ÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 000D ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Control) ÷ [0.3] ÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 000D ÷ 034F ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 000D ÷ 0308 × 034F ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000D ÷ 200C ÷ # ÷ [0.2] (CR) ÷ [4.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 000D ÷ 0308 × 200C ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 000D ÷ 0600 ÷ # ÷ [0.2] (CR) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -96,8 +94,6 @@ ÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 000D ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 000D ÷ 0900 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 000D ÷ 0308 × 0900 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 000D ÷ 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 000D ÷ 0904 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -110,8 +106,8 @@ ÷ 000D ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 000D ÷ 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 093C ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 0308 × 093C ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 0900 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 0308 × 0900 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 000D ÷ 094D ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 000D ÷ 0308 × 094D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 000D ÷ 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -126,8 +122,8 @@ ÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 000A ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Control) ÷ [0.3] ÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 000A ÷ 034F ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 000A ÷ 0308 × 034F ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000A ÷ 200C ÷ # ÷ [0.2] (LF) ÷ [4.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 000A ÷ 0308 × 200C ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 000A ÷ 0600 ÷ # ÷ [0.2] (LF) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -144,8 +140,6 @@ ÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 000A ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 000A ÷ 0900 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 000A ÷ 0308 × 0900 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 000A ÷ 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 000A ÷ 0904 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -158,8 +152,8 @@ ÷ 000A ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 000A ÷ 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 093C ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 0308 × 093C ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 0900 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 0308 × 0900 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 000A ÷ 094D ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 000A ÷ 0308 × 094D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 000A ÷ 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -174,8 +168,8 @@ ÷ 0001 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0001 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Control) ÷ [0.3] ÷ 0001 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0001 ÷ 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0001 ÷ 0308 × 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0001 ÷ 200C ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0001 ÷ 0308 × 200C ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0001 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -192,8 +186,6 @@ ÷ 0001 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0001 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0001 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0001 ÷ 0900 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0001 ÷ 0308 × 0900 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0001 ÷ 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0001 ÷ 0308 × 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0001 ÷ 0904 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -206,62 +198,60 @@ ÷ 0001 ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0001 ÷ 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 0308 × 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 093C ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 0308 × 093C ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 0900 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 0308 × 0900 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 094D ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 0308 × 094D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 0308 × 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ 0001 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Other) ÷ [0.3] ÷ 0001 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 034F ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 034F × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 034F ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (CR) ÷ [0.3] -÷ 034F × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 034F ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (LF) ÷ [0.3] -÷ 034F × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 034F ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (Control) ÷ [0.3] -÷ 034F × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 034F × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 034F × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 034F ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 034F × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 034F ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 034F × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 034F × 0A03 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 034F × 0308 × 0A03 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 034F ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 034F × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 034F ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 034F × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 034F ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 034F × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 034F ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 034F × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 034F ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 034F × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 034F × 0900 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F × 0308 × 0900 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F ÷ 0904 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 034F × 0308 ÷ 0904 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 034F ÷ 0D4E ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F × 0308 ÷ 0D4E ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 034F ÷ 0915 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 034F × 0308 ÷ 0915 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 034F ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 034F × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 034F × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 034F × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 034F × 093C ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 034F × 0308 × 093C ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 034F × 094D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 034F × 0308 × 094D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 034F × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 034F × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 034F ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] (Other) ÷ [0.3] -÷ 034F × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 200C ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 200C × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 200C ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [5.0] (CR) ÷ [0.3] +÷ 200C × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 200C ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [5.0] (LF) ÷ [0.3] +÷ 200C × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 200C ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [5.0] (Control) ÷ [0.3] +÷ 200C × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 200C × 200C ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 200C × 0308 × 200C ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 200C ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200C ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 200C × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 200C × 0A03 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200C × 0308 × 0A03 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200C ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200C × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200C ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200C × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200C ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200C × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200C ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200C × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200C ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200C × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200C × 0903 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] +÷ 200C × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] +÷ 200C ÷ 0904 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] +÷ 200C × 0308 ÷ 0904 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] +÷ 200C ÷ 0D4E ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] +÷ 200C × 0308 ÷ 0D4E ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] +÷ 200C ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] +÷ 200C × 0308 ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] +÷ 200C ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 200C × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 200C × 0300 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 200C × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 200C × 0900 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 200C × 0308 × 0900 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 200C × 094D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] +÷ 200C × 0308 × 094D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] +÷ 200C × 200D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 200C × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 200C ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] (Other) ÷ [0.3] +÷ 200C × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] ÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (CR) ÷ [0.3] @@ -270,8 +260,8 @@ ÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (Control) ÷ [0.3] ÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 1F1E6 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 1F1E6 × 0308 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1F1E6 × 200C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 1F1E6 × 0308 × 200C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1F1E6 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -288,8 +278,6 @@ ÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1F1E6 × 0900 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1F1E6 × 0308 × 0900 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1F1E6 ÷ 0904 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -302,8 +290,8 @@ ÷ 1F1E6 × 0308 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 × 093C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 × 0308 × 093C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 × 0900 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 × 0308 × 0900 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 1F1E6 × 094D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1F1E6 × 0308 × 094D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -318,8 +306,8 @@ ÷ 0600 × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0600 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (Control) ÷ [0.3] ÷ 0600 × 0308 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0600 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0600 × 0308 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0600 × 200C ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0600 × 0308 × 200C ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0600 × 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0600 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0600 × 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -336,8 +324,6 @@ ÷ 0600 × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0600 × AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0600 × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0600 × 0900 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0600 × 0308 × 0900 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0600 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0600 × 0308 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0600 × 0904 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -350,8 +336,8 @@ ÷ 0600 × 0308 ÷ 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0600 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0600 × 0308 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0600 × 093C ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0600 × 0308 × 093C ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0600 × 0900 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0600 × 0308 × 0900 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0600 × 094D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0600 × 0308 × 094D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0600 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -366,8 +352,8 @@ ÷ 0A03 × 0308 ÷ 000A ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0A03 ÷ 0001 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [5.0] (Control) ÷ [0.3] ÷ 0A03 × 0308 ÷ 0001 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0A03 × 034F ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0A03 × 0308 × 034F ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0A03 × 200C ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0A03 × 0308 × 200C ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0A03 ÷ 1F1E6 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0A03 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0A03 ÷ 0600 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -384,8 +370,6 @@ ÷ 0A03 × 0308 ÷ AC00 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0A03 ÷ AC01 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0A03 × 0308 ÷ AC01 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0A03 × 0900 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0A03 × 0308 × 0900 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0A03 × 0903 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0A03 × 0308 × 0903 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0A03 ÷ 0904 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -398,8 +382,8 @@ ÷ 0A03 × 0308 ÷ 231A ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0A03 × 0300 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0A03 × 0308 × 0300 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0A03 × 093C ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0A03 × 0308 × 093C ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0A03 × 0900 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0A03 × 0308 × 0900 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0A03 × 094D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0A03 × 0308 × 094D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0A03 × 200D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -414,8 +398,8 @@ ÷ 1100 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 1100 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (Control) ÷ [0.3] ÷ 1100 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 1100 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 1100 × 0308 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1100 × 200C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 1100 × 0308 × 200C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1100 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -432,8 +416,6 @@ ÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 1100 × AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1100 × 0900 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1100 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 1100 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1100 ÷ 0904 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -446,8 +428,8 @@ ÷ 1100 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1100 × 093C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1100 × 0308 × 093C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1100 × 0900 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1100 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 1100 × 094D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1100 × 0308 × 094D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -462,8 +444,8 @@ ÷ 1160 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 1160 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (Control) ÷ [0.3] ÷ 1160 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 1160 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 1160 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1160 × 200C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 1160 × 0308 × 200C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 1160 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -480,8 +462,6 @@ ÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 1160 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1160 × 0900 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1160 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 1160 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 1160 ÷ 0904 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -494,8 +474,8 @@ ÷ 1160 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1160 × 093C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1160 × 0308 × 093C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1160 × 0900 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 1160 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 1160 × 094D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1160 × 0308 × 094D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -510,8 +490,8 @@ ÷ 11A8 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 11A8 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (Control) ÷ [0.3] ÷ 11A8 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 11A8 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 11A8 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 11A8 × 200C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 11A8 × 0308 × 200C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 11A8 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -528,8 +508,6 @@ ÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 11A8 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 11A8 × 0900 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 11A8 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 11A8 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 11A8 ÷ 0904 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -542,8 +520,8 @@ ÷ 11A8 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 11A8 × 093C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 11A8 × 0308 × 093C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 11A8 × 0900 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 11A8 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 11A8 × 094D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 11A8 × 0308 × 094D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -558,8 +536,8 @@ ÷ AC00 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ AC00 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (Control) ÷ [0.3] ÷ AC00 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ AC00 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ AC00 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC00 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ AC00 × 0308 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ AC00 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -576,8 +554,6 @@ ÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ AC00 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ AC00 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ AC00 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ AC00 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ AC00 ÷ 0904 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -590,8 +566,8 @@ ÷ AC00 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ AC00 × 093C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ AC00 × 0308 × 093C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ AC00 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ AC00 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ AC00 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ AC00 × 0308 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -606,8 +582,8 @@ ÷ AC01 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ AC01 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (Control) ÷ [0.3] ÷ AC01 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ AC01 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ AC01 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC01 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ AC01 × 0308 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ AC01 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -624,8 +600,6 @@ ÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ AC01 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ AC01 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ AC01 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ AC01 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ AC01 ÷ 0904 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -638,62 +612,14 @@ ÷ AC01 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ AC01 × 093C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ AC01 × 0308 × 093C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ AC01 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ AC01 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ AC01 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ AC01 × 0308 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ AC01 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] (Other) ÷ [0.3] ÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0900 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0900 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0900 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [5.0] (CR) ÷ [0.3] -÷ 0900 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0900 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [5.0] (LF) ÷ [0.3] -÷ 0900 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0900 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [5.0] (Control) ÷ [0.3] -÷ 0900 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0900 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0900 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0900 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0900 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0900 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0900 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0900 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0900 × 0308 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0900 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0900 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0900 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0900 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0900 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0900 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0900 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0900 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0900 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0900 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0900 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0308 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0308 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0900 × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0900 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0900 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0900 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0900 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0900 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0900 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0900 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [999.0] (Other) ÷ [0.3] -÷ 0900 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] ÷ 0903 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 0903 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [5.0] (CR) ÷ [0.3] @@ -702,8 +628,8 @@ ÷ 0903 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0903 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [5.0] (Control) ÷ [0.3] ÷ 0903 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0903 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0903 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0903 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0903 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0903 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -720,8 +646,6 @@ ÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0903 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0903 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0903 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0903 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0903 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -734,8 +658,8 @@ ÷ 0903 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0903 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0903 × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0903 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0903 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0903 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0903 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -750,8 +674,8 @@ ÷ 0904 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0904 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [5.0] (Control) ÷ [0.3] ÷ 0904 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0904 × 034F ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0904 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0904 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0904 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0904 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0904 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0904 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -768,8 +692,6 @@ ÷ 0904 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0904 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0904 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0904 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0904 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0904 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0904 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0904 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -782,8 +704,8 @@ ÷ 0904 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0904 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0904 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0904 × 093C ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0904 × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0904 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0904 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0904 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0904 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0904 × 200D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -798,8 +720,8 @@ ÷ 0D4E × 0308 ÷ 000A ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0D4E ÷ 0001 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [5.0] (Control) ÷ [0.3] ÷ 0D4E × 0308 ÷ 0001 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0D4E × 034F ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0D4E × 0308 × 034F ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0D4E × 200C ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0D4E × 0308 × 200C ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0D4E × 1F1E6 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0D4E × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0D4E × 0600 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -816,8 +738,6 @@ ÷ 0D4E × 0308 ÷ AC00 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0D4E × AC01 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0D4E × 0308 ÷ AC01 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0D4E × 0900 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0D4E × 0308 × 0900 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0D4E × 0903 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0D4E × 0308 × 0903 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0D4E × 0904 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -830,8 +750,8 @@ ÷ 0D4E × 0308 ÷ 231A ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0D4E × 0300 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0D4E × 0308 × 0300 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 093C ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 0308 × 093C ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0D4E × 0900 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0D4E × 0308 × 0900 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0D4E × 094D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0D4E × 0308 × 094D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0D4E × 200D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -846,8 +766,8 @@ ÷ 0915 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0915 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [5.0] (Control) ÷ [0.3] ÷ 0915 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0915 × 034F ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0915 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0915 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0915 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0915 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0915 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0915 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -864,8 +784,6 @@ ÷ 0915 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0915 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0915 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0915 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0915 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0915 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0915 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0915 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -878,8 +796,8 @@ ÷ 0915 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0915 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0915 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0915 × 093C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0915 × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0915 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0915 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0915 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0915 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0915 × 200D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -894,8 +812,8 @@ ÷ 231A × 0308 ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 231A ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (Control) ÷ [0.3] ÷ 231A × 0308 ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 231A × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 231A × 0308 × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 231A × 200C ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 231A × 0308 × 200C ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 231A ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 231A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 231A ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -912,8 +830,6 @@ ÷ 231A × 0308 ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 231A ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 231A × 0308 ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 231A × 0900 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 231A × 0308 × 0900 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 231A × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 231A × 0308 × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 231A ÷ 0904 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -926,8 +842,8 @@ ÷ 231A × 0308 ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 231A × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 231A × 0308 × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 231A × 093C ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 231A × 0308 × 093C ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 231A × 0900 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 231A × 0308 × 0900 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 231A × 094D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 231A × 0308 × 094D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 231A × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -942,8 +858,8 @@ ÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] ÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0300 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0300 × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0300 × 200C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0300 × 0308 × 200C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0300 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -960,8 +876,6 @@ ÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0300 × 0900 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0300 × 0308 × 0900 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0300 ÷ 0904 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -974,62 +888,60 @@ ÷ 0300 × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0300 × 093C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0300 × 0308 × 093C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0300 × 0900 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0300 × 0308 × 0900 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0300 × 094D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0300 × 0308 × 094D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] ÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] ÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 093C ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 093C × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 093C ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 093C × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 093C ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 093C × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 093C ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 093C × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 093C × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 093C × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 093C ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 093C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 093C ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 093C × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 093C × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 093C × 0308 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 093C ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 093C × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 093C ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 093C × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 093C ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 093C × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 093C ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 093C × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 093C ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 093C × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 093C × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 093C × 0308 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 093C ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C × 0308 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 093C ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 093C × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 093C ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 093C × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 093C × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 093C × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 093C × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 093C × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 093C × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 093C × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 093C × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 093C × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 093C ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 093C × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0900 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0900 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0900 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0900 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0900 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0900 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0900 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0900 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0900 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0900 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0900 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0900 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0900 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0900 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0900 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0900 × 0308 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0900 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0900 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0900 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0900 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0900 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0900 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0900 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0900 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0900 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0900 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0900 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 × 0308 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 × 0308 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] +÷ 0900 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] +÷ 0900 × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] +÷ 0900 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0900 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0900 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0900 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0900 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0900 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0900 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] +÷ 0900 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] +÷ 0900 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0900 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0900 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0900 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] ÷ 094D ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 094D × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 094D ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] @@ -1038,8 +950,8 @@ ÷ 094D × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 094D ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] ÷ 094D × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 094D × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 094D × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 094D × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 094D × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 094D ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 094D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 094D ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -1056,8 +968,6 @@ ÷ 094D × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 094D ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 094D × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 094D × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 094D × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 094D × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 094D × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 094D ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -1070,8 +980,8 @@ ÷ 094D × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 094D × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 094D × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 094D × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 094D × 0308 × 093C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 094D × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 094D × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 094D × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 094D × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 094D × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -1086,8 +996,8 @@ ÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] ÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 200D × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 200D × 0308 × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 200D × 200C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 200D × 0308 × 200C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 200D ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -1104,8 +1014,6 @@ ÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 200D × 0900 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 200D × 0308 × 0900 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 200D ÷ 0904 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -1118,8 +1026,8 @@ ÷ 200D × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 200D × 093C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 200D × 0308 × 093C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 200D × 0900 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 200D × 0308 × 0900 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 200D × 094D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 200D × 0308 × 094D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -1134,8 +1042,8 @@ ÷ 0378 × 0308 ÷ 000A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] ÷ 0378 ÷ 0001 ÷ # ÷ [0.2] (Other) ÷ [5.0] (Control) ÷ [0.3] ÷ 0378 × 0308 ÷ 0001 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0378 × 034F ÷ # ÷ [0.2] (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] -÷ 0378 × 0308 × 034F ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0378 × 200C ÷ # ÷ [0.2] (Other) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 0378 × 0308 × 200C ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] ÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0378 ÷ 0600 ÷ # ÷ [0.2] (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] @@ -1152,8 +1060,6 @@ ÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0378 ÷ AC01 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0378 × 0900 ÷ # ÷ [0.2] (Other) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0378 × 0308 × 0900 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts) ÷ [0.3] ÷ 0378 × 0903 ÷ # ÷ [0.2] (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] ÷ 0378 ÷ 0904 ÷ # ÷ [0.2] (Other) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] @@ -1166,8 +1072,8 @@ ÷ 0378 × 0308 ÷ 231A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] ÷ 0378 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] ÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0378 × 093C ÷ # ÷ [0.2] (Other) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0378 × 0308 × 093C ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0378 × 0900 ÷ # ÷ [0.2] (Other) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] +÷ 0378 × 0308 × 0900 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] ÷ 0378 × 094D ÷ # ÷ [0.2] (Other) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0378 × 0308 × 094D ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] ÷ 0378 × 200D ÷ # ÷ [0.2] (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] @@ -1190,10 +1096,10 @@ ÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] ÷ 0061 × 0903 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] ÷ 0061 ÷ 0600 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) × [9.2] LATIN SMALL LETTER B (Other) ÷ [0.3] -÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3] -÷ 0061 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3] -÷ 0061 × 1F3FF ÷ 1F476 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] -÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [0.3] +÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 0061 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 0061 × 1F3FF ÷ 1F476 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [999.0] BABY (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [0.3] ÷ 1F6D1 × 200D × 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] ÷ 0061 × 200D ÷ 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] ÷ 2701 × 200D × 2701 ÷ # ÷ [0.2] UPPER BLADE SCISSORS (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] UPPER BLADE SCISSORS (Other) ÷ [0.3] @@ -1210,6 +1116,6 @@ ÷ 003F × 094D ÷ 0924 ÷ # ÷ [0.2] QUESTION MARK (Other) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] ÷ 0915 × 094D × 094D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.3] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] # -# Lines: 1187 +# Lines: 1093 # # EOF diff --git a/libcxx/utils/data/unicode/emoji-data.txt b/libcxx/utils/data/unicode/emoji-data.txt index 0ba10e9ce4c9ac..ff99028248b5fa 100644 --- a/libcxx/utils/data/unicode/emoji-data.txt +++ b/libcxx/utils/data/unicode/emoji-data.txt @@ -1,11 +1,11 @@ # emoji-data.txt -# Date: 2023-02-01, 02:22:54 GMT -# © 2023 Unicode®, Inc. +# Date: 2024-05-01, 21:25:24 GMT +# © 2024 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html +# For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Emoji Data for UTS #51 -# Used with Emoji Version 15.1 and subsequent minor revisions (if any) +# Used with Emoji Version 16.0 and subsequent minor revisions (if any) # # For documentation and usage, see https://www.unicode.org/reports/tr51 # @@ -407,6 +407,8 @@ 1FA80..1FA82 ; Emoji # E12.0 [3] (🪀..🪂) yo-yo..parachute 1FA83..1FA86 ; Emoji # E13.0 [4] (🪃..🪆) boomerang..nesting dolls 1FA87..1FA88 ; Emoji # E15.0 [2] (🪇..🪈) maracas..flute +1FA89 ; Emoji # E16.0 [1] (🪉) harp +1FA8F ; Emoji # E16.0 [1] (🪏) shovel 1FA90..1FA95 ; Emoji # E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Emoji # E13.0 [19] (🪖..🪨) military helmet..rock 1FAA9..1FAAC ; Emoji # E14.0 [4] (🪩..🪬) mirror ball..hamsa @@ -414,19 +416,24 @@ 1FAB0..1FAB6 ; Emoji # E13.0 [7] (🪰..🪶) fly..feather 1FAB7..1FABA ; Emoji # E14.0 [4] (🪷..🪺) lotus..nest with eggs 1FABB..1FABD ; Emoji # E15.0 [3] (🪻..🪽) hyacinth..wing +1FABE ; Emoji # E16.0 [1] (🪾) leafless tree 1FABF ; Emoji # E15.0 [1] (🪿) goose 1FAC0..1FAC2 ; Emoji # E13.0 [3] (🫀..🫂) anatomical heart..people hugging 1FAC3..1FAC5 ; Emoji # E14.0 [3] (🫃..🫅) pregnant man..person with crown +1FAC6 ; Emoji # E16.0 [1] (🫆) fingerprint 1FACE..1FACF ; Emoji # E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Emoji # E13.0 [7] (🫐..🫖) blueberries..teapot 1FAD7..1FAD9 ; Emoji # E14.0 [3] (🫗..🫙) pouring liquid..jar 1FADA..1FADB ; Emoji # E15.0 [2] (🫚..🫛) ginger root..pea pod +1FADC ; Emoji # E16.0 [1] (🫜) root vegetable +1FADF ; Emoji # E16.0 [1] (🫟) splatter 1FAE0..1FAE7 ; Emoji # E14.0 [8] (🫠..🫧) melting face..bubbles 1FAE8 ; Emoji # E15.0 [1] (🫨) shaking face +1FAE9 ; Emoji # E16.0 [1] (🫩) face with bags under eyes 1FAF0..1FAF6 ; Emoji # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands 1FAF7..1FAF8 ; Emoji # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand -# Total elements: 1424 +# Total elements: 1431 # ================================================ @@ -696,6 +703,8 @@ 1FA80..1FA82 ; Emoji_Presentation # E12.0 [3] (🪀..🪂) yo-yo..parachute 1FA83..1FA86 ; Emoji_Presentation # E13.0 [4] (🪃..🪆) boomerang..nesting dolls 1FA87..1FA88 ; Emoji_Presentation # E15.0 [2] (🪇..🪈) maracas..flute +1FA89 ; Emoji_Presentation # E16.0 [1] (🪉) harp +1FA8F ; Emoji_Presentation # E16.0 [1] (🪏) shovel 1FA90..1FA95 ; Emoji_Presentation # E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Emoji_Presentation # E13.0 [19] (🪖..🪨) military helmet..rock 1FAA9..1FAAC ; Emoji_Presentation # E14.0 [4] (🪩..🪬) mirror ball..hamsa @@ -703,19 +712,24 @@ 1FAB0..1FAB6 ; Emoji_Presentation # E13.0 [7] (🪰..🪶) fly..feather 1FAB7..1FABA ; Emoji_Presentation # E14.0 [4] (🪷..🪺) lotus..nest with eggs 1FABB..1FABD ; Emoji_Presentation # E15.0 [3] (🪻..🪽) hyacinth..wing +1FABE ; Emoji_Presentation # E16.0 [1] (🪾) leafless tree 1FABF ; Emoji_Presentation # E15.0 [1] (🪿) goose 1FAC0..1FAC2 ; Emoji_Presentation # E13.0 [3] (🫀..🫂) anatomical heart..people hugging 1FAC3..1FAC5 ; Emoji_Presentation # E14.0 [3] (🫃..🫅) pregnant man..person with crown +1FAC6 ; Emoji_Presentation # E16.0 [1] (🫆) fingerprint 1FACE..1FACF ; Emoji_Presentation # E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Emoji_Presentation # E13.0 [7] (🫐..🫖) blueberries..teapot 1FAD7..1FAD9 ; Emoji_Presentation # E14.0 [3] (🫗..🫙) pouring liquid..jar 1FADA..1FADB ; Emoji_Presentation # E15.0 [2] (🫚..🫛) ginger root..pea pod +1FADC ; Emoji_Presentation # E16.0 [1] (🫜) root vegetable +1FADF ; Emoji_Presentation # E16.0 [1] (🫟) splatter 1FAE0..1FAE7 ; Emoji_Presentation # E14.0 [8] (🫠..🫧) melting face..bubbles 1FAE8 ; Emoji_Presentation # E15.0 [1] (🫨) shaking face +1FAE9 ; Emoji_Presentation # E16.0 [1] (🫩) face with bags under eyes 1FAF0..1FAF6 ; Emoji_Presentation # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands 1FAF7..1FAF8 ; Emoji_Presentation # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand -# Total elements: 1205 +# Total elements: 1212 # ================================================ @@ -1289,7 +1303,9 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1FA80..1FA82 ; Extended_Pictographic# E12.0 [3] (🪀..🪂) yo-yo..parachute 1FA83..1FA86 ; Extended_Pictographic# E13.0 [4] (🪃..🪆) boomerang..nesting dolls 1FA87..1FA88 ; Extended_Pictographic# E15.0 [2] (🪇..🪈) maracas..flute -1FA89..1FA8F ; Extended_Pictographic# E0.0 [7] (🪉..🪏) .. +1FA89 ; Extended_Pictographic# E16.0 [1] (🪉) harp +1FA8A..1FA8E ; Extended_Pictographic# E0.0 [5] (🪊..🪎) .. +1FA8F ; Extended_Pictographic# E16.0 [1] (🪏) shovel 1FA90..1FA95 ; Extended_Pictographic# E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Extended_Pictographic# E13.0 [19] (🪖..🪨) military helmet..rock 1FAA9..1FAAC ; Extended_Pictographic# E14.0 [4] (🪩..🪬) mirror ball..hamsa @@ -1297,19 +1313,23 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1FAB0..1FAB6 ; Extended_Pictographic# E13.0 [7] (🪰..🪶) fly..feather 1FAB7..1FABA ; Extended_Pictographic# E14.0 [4] (🪷..🪺) lotus..nest with eggs 1FABB..1FABD ; Extended_Pictographic# E15.0 [3] (🪻..🪽) hyacinth..wing -1FABE ; Extended_Pictographic# E0.0 [1] (🪾) +1FABE ; Extended_Pictographic# E16.0 [1] (🪾) leafless tree 1FABF ; Extended_Pictographic# E15.0 [1] (🪿) goose 1FAC0..1FAC2 ; Extended_Pictographic# E13.0 [3] (🫀..🫂) anatomical heart..people hugging 1FAC3..1FAC5 ; Extended_Pictographic# E14.0 [3] (🫃..🫅) pregnant man..person with crown -1FAC6..1FACD ; Extended_Pictographic# E0.0 [8] (🫆..🫍) .. +1FAC6 ; Extended_Pictographic# E16.0 [1] (🫆) fingerprint +1FAC7..1FACD ; Extended_Pictographic# E0.0 [7] (🫇..🫍) .. 1FACE..1FACF ; Extended_Pictographic# E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Extended_Pictographic# E13.0 [7] (🫐..🫖) blueberries..teapot 1FAD7..1FAD9 ; Extended_Pictographic# E14.0 [3] (🫗..🫙) pouring liquid..jar 1FADA..1FADB ; Extended_Pictographic# E15.0 [2] (🫚..🫛) ginger root..pea pod -1FADC..1FADF ; Extended_Pictographic# E0.0 [4] (🫜..🫟) .. +1FADC ; Extended_Pictographic# E16.0 [1] (🫜) root vegetable +1FADD..1FADE ; Extended_Pictographic# E0.0 [2] (🫝..🫞) .. +1FADF ; Extended_Pictographic# E16.0 [1] (🫟) splatter 1FAE0..1FAE7 ; Extended_Pictographic# E14.0 [8] (🫠..🫧) melting face..bubbles 1FAE8 ; Extended_Pictographic# E15.0 [1] (🫨) shaking face -1FAE9..1FAEF ; Extended_Pictographic# E0.0 [7] (🫩..🫯) .. +1FAE9 ; Extended_Pictographic# E16.0 [1] (🫩) face with bags under eyes +1FAEA..1FAEF ; Extended_Pictographic# E0.0 [6] (🫪..🫯) .. 1FAF0..1FAF6 ; Extended_Pictographic# E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands 1FAF7..1FAF8 ; Extended_Pictographic# E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand 1FAF9..1FAFF ; Extended_Pictographic# E0.0 [7] (🫹..🫿) .. From libcxx-commits at lists.llvm.org Tue Feb 4 09:55:30 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 09:55:30 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036) (PR #125587) In-Reply-To: Message-ID: <67a25492.170a0220.3c8c90.d6ca@mx.google.com> ldionne wrote: My strong preference would be to include a standard header instead, but that would require LLVM libc to define its detection macro when such header is included. I'd be okay with a partial revert only, but @jhuber6 would have to tell me what the check should be instead. https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Tue Feb 4 09:59:23 2025 From: libcxx-commits at lists.llvm.org (Joseph Huber via libcxx-commits) Date: Tue, 04 Feb 2025 09:59:23 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036) (PR #125587) In-Reply-To: Message-ID: <67a2557b.170a0220.2740ac.3df8@mx.google.com> jhuber6 wrote: > My strong preference would be to include a standard header instead, but that would require LLVM libc to define its detection macro when such header is included. > > I'd be okay with a partial revert only, but @jhuber6 would have to tell me what the check should be instead. I think we already have a handful of `__LLVM_LIBC__` tests that might also break on baremetal, cc @petrhosek. > LLVM libc should instead provide a more standard way of getting configuration macros like LLVM_LIBC. But `features.h` is the standard way on Linux at least. We could always emit `__features.h` or something if we're really concerned. https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Tue Feb 4 10:04:28 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 10:04:28 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Also provide an alignment assumption for vector in C++03 mode (PR #124839) In-Reply-To: Message-ID: <67a256ac.170a0220.18a399.38fe@mx.google.com> https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/124839 >From bba08e739257f76cc161fa70eed12001870d2289 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 28 Jan 2025 16:11:44 -0500 Subject: [PATCH] [libc++] Also provide an alignment assumption for vector in C++03 mode There's no reason not to, and it's easy enough to do using enable_if. As a drive-by change, also add a missing _LIBCPP_NO_CFI attribute on __add_alignment_assumption. --- libcxx/include/__vector/vector.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h index 66cb622e209633..2a79868c94b2cc 100644 --- a/libcxx/include/__vector/vector.h +++ b/libcxx/include/__vector/vector.h @@ -783,14 +783,18 @@ class _LIBCPP_TEMPLATE_VIS vector { _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(vector&, false_type) _NOEXCEPT {} - static _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __add_alignment_assumption(pointer __p) _NOEXCEPT { -#ifndef _LIBCPP_CXX03_LANG - if constexpr (is_pointer::value) { - if (!__libcpp_is_constant_evaluated()) { - return static_cast(__builtin_assume_aligned(__p, alignof(decltype(*__p)))); - } + template ::value, int> = 0> + static _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI pointer + __add_alignment_assumption(_Ptr __p) _NOEXCEPT { + if (!__libcpp_is_constant_evaluated()) { + return static_cast(__builtin_assume_aligned(__p, alignof(decltype(*__p)))); } -#endif + return __p; + } + + template ::value, int> = 0> + static _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI pointer + __add_alignment_assumption(_Ptr __p) _NOEXCEPT { return __p; } }; From libcxx-commits at lists.llvm.org Tue Feb 4 10:47:19 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Tue, 04 Feb 2025 10:47:19 -0800 (PST) Subject: [libcxx-commits] [libcxx] Fixed Reference copy and move assignment operators (PR #125723) In-Reply-To: Message-ID: <67a260b7.a70a0220.72749.30ea@mx.google.com> mordante wrote: Thanks for your patch! Can you please add a description explaining what this patch tries to fix? https://github.com/llvm/llvm-project/pull/125723 From libcxx-commits at lists.llvm.org Tue Feb 4 11:30:32 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 11:30:32 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Revert "Do not redeclare lgamma_r when targeting the LLVM C library (#102036) (PR #125587) In-Reply-To: Message-ID: <67a26ad8.170a0220.33936.0b81@mx.google.com> https://github.com/ldionne edited https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Tue Feb 4 11:30:36 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 11:30:36 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Avoid including on arbitrary platforms (PR #125587) In-Reply-To: Message-ID: <67a26adc.170a0220.ff18b.e80f@mx.google.com> https://github.com/ldionne edited https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Tue Feb 4 11:38:43 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 11:38:43 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a26cc3.170a0220.29c49.4415@mx.google.com> ldionne wrote: The compiler's `-fno-sized-deallocation` flag allows controlling whether delete expressions should use sized delete or not, which is a breaking change for some code, since it changes which `operator delete` gets called without making any changes to the user code. AFAIU, that's the purpose of that flag and that's the reason why it wasn't made the default until recently (upstream). Some users might be in a situation where they don't want their `delete` expressions to resolve differently, but where it is 100% acceptable to call the sized `operator delete` explicitly. In that case, they could pass `-fno-sized-deallocation` yet still call the library function explicitly (after this patch, but not before). For availability issues, we have attributes on these declarations: if someone attempts to use a sized `operator delete` while compiling for a target that does not support the functionality, that should be caught at compile-time by these attributes. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Tue Feb 4 11:38:51 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 11:38:51 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a26ccb.170a0220.398000.ef66@mx.google.com> https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/125577 >From 35aeeb6e70b63999f610e479b4d11db20213551d Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 3 Feb 2025 15:47:01 -0500 Subject: [PATCH 1/2] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation After ef804d8f9b4, we stopped providing the declaration of sized deallocation functions unless the compiler provides support for the language feature. In reality, we can still provide the declarations of global operator delete for users who want to call these operators directly without going through the compiler rewrite. --- libcxx/include/__new/global_new_delete.h | 2 +- ...zed_delete.fno-sized-deallocation.pass.cpp | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp diff --git a/libcxx/include/__new/global_new_delete.h b/libcxx/include/__new/global_new_delete.h index 96510ab56b00b5..3d1f7b6f3d2409 100644 --- a/libcxx/include/__new/global_new_delete.h +++ b/libcxx/include/__new/global_new_delete.h @@ -25,7 +25,7 @@ # define _THROW_BAD_ALLOC #endif -#if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L +#if _LIBCPP_STD_VER >= 14 # define _LIBCPP_HAS_SIZED_DEALLOCATION 1 #else # define _LIBCPP_HAS_SIZED_DEALLOCATION 0 diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp new file mode 100644 index 00000000000000..daa0374fd28125 --- /dev/null +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Ensure that libc++ still provides the declaration of sized operator delete even +// when sized deallocation support is disabled at the language level, since it should +// still be valid to call these operators explicitly (as opposed to via a compiler +// rewrite of a delete expression). + +// UNSUPPORTED: c++03, c++11 + +// ADDITIONAL_COMPILE_FLAGS: -fno-sized-deallocation + +// Sized deallocation support was introduced in LLVM 11 +// XFAIL: using-built-library-before-llvm-11 + +#include + +int main(int, char**) { + void* p = ::operator new(10); + ::operator delete(p, 10); + return 0; +} >From e6864e9df0ada615f24eba42829986da527e50bb Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 4 Feb 2025 14:33:16 -0500 Subject: [PATCH 2/2] Format --- .../sized_delete.fno-sized-deallocation.pass.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp index daa0374fd28125..f6145cb1eba741 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.fno-sized-deallocation.pass.cpp @@ -21,7 +21,7 @@ #include int main(int, char**) { - void* p = ::operator new(10); - ::operator delete(p, 10); - return 0; + void* p = ::operator new(10); + ::operator delete(p, 10); + return 0; } From libcxx-commits at lists.llvm.org Tue Feb 4 11:45:19 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 11:45:19 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Replace __is_trivially_relocatable by is_trivially_copyable (PR #124970) In-Reply-To: Message-ID: <67a26e4f.170a0220.1f69c2.e514@mx.google.com> https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/124970 >From 6da2fc4d827722f0adc5e445232d62fb191d3a61 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 29 Jan 2025 13:18:11 -0500 Subject: [PATCH 1/3] [libc++] Replace __is_trivially_relocatable by is_trivially_copyable The __is_trivially_relocatable builtin has semantics that do not correspond to any current or future notion of trivial relocation. Furthermore, it currently leads to incorrect optimizations for some types on supported compilers: - Clang on Windows where types with non-trivial destructors get incorrectly optimized - AppleClang where types with non-trivial move constructors get incorrectly optimized Until there is an agreed upon and bugfree implementation of what it means to be trivially relocatable, it is safer to simply use trivially copyable instead. This doesn't leave a lot of types behind and is definitely correct. --- .../__type_traits/is_trivially_relocatable.h | 7 -- .../is_trivially_relocatable.compile.pass.cpp | 10 +++ .../vector/trivial_relocation.pass.cpp | 67 +++++++++++++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp diff --git a/libcxx/include/__type_traits/is_trivially_relocatable.h b/libcxx/include/__type_traits/is_trivially_relocatable.h index c0871731cc0016b..ecc97a41dfbdcbd 100644 --- a/libcxx/include/__type_traits/is_trivially_relocatable.h +++ b/libcxx/include/__type_traits/is_trivially_relocatable.h @@ -11,7 +11,6 @@ #include <__config> #include <__type_traits/enable_if.h> -#include <__type_traits/integral_constant.h> #include <__type_traits/is_same.h> #include <__type_traits/is_trivially_copyable.h> @@ -23,14 +22,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD // A type is trivially relocatable if a move construct + destroy of the original object is equivalent to // `memcpy(dst, src, sizeof(T))`. - -#if __has_builtin(__is_trivially_relocatable) -template -struct __libcpp_is_trivially_relocatable : integral_constant {}; -#else template struct __libcpp_is_trivially_relocatable : is_trivially_copyable<_Tp> {}; -#endif template struct __libcpp_is_trivially_relocatable<_Tp, diff --git a/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp index 674df1d0219057d..e43f38aa26f7d0a 100644 --- a/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp +++ b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp @@ -60,6 +60,16 @@ static_assert(std::__libcpp_is_trivially_relocatable: static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); #endif +struct NonTrivialMoveConstructor { + NonTrivialMoveConstructor(NonTrivialMoveConstructor&&); +}; +static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + +struct NonTrivialDestructor { + ~NonTrivialDestructor() {} +}; +static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + // library-internal types // ---------------------- diff --git a/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp b/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp new file mode 100644 index 000000000000000..e109a5034032ddb --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// Make sure we don't miscompile vector operations for types that shouldn't be considered +// trivially relocatable. + +#include +#include +#include + +#include "test_macros.h" + +struct Tracker { + std::size_t move_constructs = 0; +}; + +struct [[clang::trivial_abi]] Inner { + TEST_CONSTEXPR explicit Inner(Tracker* tracker) : tracker_(tracker) {} + TEST_CONSTEXPR Inner(const Inner& rhs) : tracker_(rhs.tracker_) { tracker_->move_constructs += 1; } + TEST_CONSTEXPR Inner(Inner&& rhs) : tracker_(rhs.tracker_) { tracker_->move_constructs += 1; } + Tracker* tracker_; +}; + +// Even though this type contains a trivial_abi type, it is not trivially move-constructible, +// so we should not attempt to optimize its move construction + destroy using trivial relocation. +struct NotTriviallyMovable { + TEST_CONSTEXPR explicit NotTriviallyMovable(Tracker* tracker) : inner_(tracker) {} + TEST_CONSTEXPR NotTriviallyMovable(NotTriviallyMovable&& other) : inner_(std::move(other.inner_)) {} + Inner inner_; +}; +static_assert(!std::is_trivially_copyable::value, ""); +LIBCPP_STATIC_ASSERT(!std::__libcpp_is_trivially_relocatable::value, ""); + +TEST_CONSTEXPR_CXX20 bool tests() { + Tracker track; + std::vector v; + + // Fill the vector at its capacity, such that any subsequent push_back would require growing. + v.reserve(5); + for (std::size_t i = 0; i != 5; ++i) { + v.emplace_back(&track); + } + assert(track.move_constructs == 0); + assert(v.size() == 5); + + // Force a reallocation of the buffer + relocalization of the elements. + // All the existing elements of the vector should be move-constructed to their new location. + v.emplace_back(&track); + assert(track.move_constructs == 5); + + return true; +} + +int main(int, char**) { + tests(); +#if TEST_STD_VER >= 20 + static_assert(tests()); +#endif + return 0; +} >From 798bb8067126208fc665d23a0d1b46f5820c9e59 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 4 Feb 2025 14:41:28 -0500 Subject: [PATCH 2/3] Use && 0 and add a comment --- libcxx/include/__type_traits/is_trivially_relocatable.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libcxx/include/__type_traits/is_trivially_relocatable.h b/libcxx/include/__type_traits/is_trivially_relocatable.h index ecc97a41dfbdcbd..9b0e240de55f4ec 100644 --- a/libcxx/include/__type_traits/is_trivially_relocatable.h +++ b/libcxx/include/__type_traits/is_trivially_relocatable.h @@ -22,8 +22,17 @@ _LIBCPP_BEGIN_NAMESPACE_STD // A type is trivially relocatable if a move construct + destroy of the original object is equivalent to // `memcpy(dst, src, sizeof(T))`. +// +// Note that we don't use the __is_trivially_relocatable Clang builtin right now because it does not +// implement the semantics of any current or future trivial relocation proposal and it can lead to +// incorrect optimizations on some platforms (Windows) and supported compilers (AppleClang). +#if __has_builtin(__is_trivially_relocatable) && 0 +template +struct __libcpp_is_trivially_relocatable : integral_constant {}; +#else template struct __libcpp_is_trivially_relocatable : is_trivially_copyable<_Tp> {}; +#endif template struct __libcpp_is_trivially_relocatable<_Tp, >From 55eaf470a98736e6ac2cfa7eb68d3a812bb0d233 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 4 Feb 2025 14:45:04 -0500 Subject: [PATCH 3/3] Make test portable --- .../sequences/vector/trivial_relocation.pass.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp b/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp index e109a5034032ddb..d093ae8b8771656 100644 --- a/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp @@ -44,16 +44,18 @@ TEST_CONSTEXPR_CXX20 bool tests() { // Fill the vector at its capacity, such that any subsequent push_back would require growing. v.reserve(5); - for (std::size_t i = 0; i != 5; ++i) { + std::size_t const capacity = v.capacity(); // could technically be more than 5 + while (v.size() < v.capacity()) { v.emplace_back(&track); } assert(track.move_constructs == 0); - assert(v.size() == 5); + assert(v.capacity() == capacity); + assert(v.size() == capacity); // Force a reallocation of the buffer + relocalization of the elements. // All the existing elements of the vector should be move-constructed to their new location. v.emplace_back(&track); - assert(track.move_constructs == 5); + assert(track.move_constructs == capacity); return true; } From libcxx-commits at lists.llvm.org Tue Feb 4 11:48:46 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 11:48:46 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Also provide an alignment assumption for vector in C++03 mode (PR #124839) In-Reply-To: Message-ID: <67a26f1e.170a0220.29c49.44e4@mx.google.com> https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/124839 >From bba08e739257f76cc161fa70eed12001870d2289 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 28 Jan 2025 16:11:44 -0500 Subject: [PATCH 1/2] [libc++] Also provide an alignment assumption for vector in C++03 mode There's no reason not to, and it's easy enough to do using enable_if. As a drive-by change, also add a missing _LIBCPP_NO_CFI attribute on __add_alignment_assumption. --- libcxx/include/__vector/vector.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h index 66cb622e209633..2a79868c94b2cc 100644 --- a/libcxx/include/__vector/vector.h +++ b/libcxx/include/__vector/vector.h @@ -783,14 +783,18 @@ class _LIBCPP_TEMPLATE_VIS vector { _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(vector&, false_type) _NOEXCEPT {} - static _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __add_alignment_assumption(pointer __p) _NOEXCEPT { -#ifndef _LIBCPP_CXX03_LANG - if constexpr (is_pointer::value) { - if (!__libcpp_is_constant_evaluated()) { - return static_cast(__builtin_assume_aligned(__p, alignof(decltype(*__p)))); - } + template ::value, int> = 0> + static _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI pointer + __add_alignment_assumption(_Ptr __p) _NOEXCEPT { + if (!__libcpp_is_constant_evaluated()) { + return static_cast(__builtin_assume_aligned(__p, alignof(decltype(*__p)))); } -#endif + return __p; + } + + template ::value, int> = 0> + static _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI pointer + __add_alignment_assumption(_Ptr __p) _NOEXCEPT { return __p; } }; >From 1e837266ad4ab7b12c9fbc60d27b776be6dc6fd0 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 4 Feb 2025 14:48:21 -0500 Subject: [PATCH 2/2] _LIBCPP_ALIGNOF --- libcxx/include/__vector/vector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h index 2a79868c94b2cc..bad676a56a8e64 100644 --- a/libcxx/include/__vector/vector.h +++ b/libcxx/include/__vector/vector.h @@ -787,7 +787,7 @@ class _LIBCPP_TEMPLATE_VIS vector { static _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI pointer __add_alignment_assumption(_Ptr __p) _NOEXCEPT { if (!__libcpp_is_constant_evaluated()) { - return static_cast(__builtin_assume_aligned(__p, alignof(decltype(*__p)))); + return static_cast(__builtin_assume_aligned(__p, _LIBCPP_ALIGNOF(decltype(*__p)))); } return __p; } From libcxx-commits at lists.llvm.org Tue Feb 4 12:43:08 2025 From: libcxx-commits at lists.llvm.org (Mark de Wever via libcxx-commits) Date: Tue, 04 Feb 2025 12:43:08 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][chrono] implements TAI clock. (PR #125550) In-Reply-To: Message-ID: <67a27bdc.050a0220.1337c6.63d8@mx.google.com> https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/125550 >From 198180b2791c4e64886ff9bd81fb2d31ef45f23a Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sat, 25 Jan 2025 20:27:14 +0100 Subject: [PATCH 1/5] [libc++][chrono] implements TAI clock. Implements parts of: - P0355 Extending to Calendars and Time Zones - P1361 Integration of chrono with text formatting - LWG3359 leap second support should allow for negative leap seconds --- libcxx/docs/Status/FormatPaper.csv | 2 +- libcxx/include/CMakeLists.txt | 1 + libcxx/include/__chrono/convert_to_tm.h | 13 + libcxx/include/__chrono/formatter.h | 14 + libcxx/include/__chrono/ostream.h | 7 + libcxx/include/__chrono/tai_clock.h | 98 ++ libcxx/include/chrono | 31 + libcxx/include/module.modulemap | 4 + libcxx/modules/std/chrono.inc | 2 +- .../diagnostics/chrono.nodiscard.verify.cpp | 11 + .../time.clock.tai/tai_time.ostream.pass.cpp | 164 +++ .../time.clock.tai.members/from_utc.pass.cpp | 159 +++ .../time.clock.tai.members/now.pass.cpp | 30 + .../time.clock.tai.members/to_utc.pass.cpp | 161 +++ .../time.clock.tai/types.compile.pass.cpp | 59 ++ .../time/time.syn/formatter.tai_time.pass.cpp | 998 ++++++++++++++++++ libcxx/test/support/concat_macros.h | 5 + 17 files changed, 1757 insertions(+), 2 deletions(-) create mode 100644 libcxx/include/__chrono/tai_clock.h create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp create mode 100644 libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp create mode 100644 libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp diff --git a/libcxx/docs/Status/FormatPaper.csv b/libcxx/docs/Status/FormatPaper.csv index 343fa62f135654..de64e9c25a7771 100644 --- a/libcxx/docs/Status/FormatPaper.csv +++ b/libcxx/docs/Status/FormatPaper.csv @@ -3,7 +3,7 @@ Section,Description,Dependencies,Assignee,Status,First released version `[time.syn] `_,"Formatter ``chrono::duration``",,Mark de Wever,|Complete|,16 `[time.syn] `_,"Formatter ``chrono::sys_time``",,Mark de Wever,|Complete|,17 `[time.syn] `_,"Formatter ``chrono::utc_time``",A ```` implementation,Mark de Wever,|Complete|,20 -`[time.syn] `_,"Formatter ``chrono::tai_time``",A ```` implementation,Mark de Wever,,, ++`[time.syn] `_,"Formatter ``chrono::tai_time``",,Mark de Wever,|Complete|,21 `[time.syn] `_,"Formatter ``chrono::gps_time``",A ```` implementation,Mark de Wever,,, `[time.syn] `_,"Formatter ``chrono::file_time``",,Mark de Wever,|Complete|,17 `[time.syn] `_,"Formatter ``chrono::local_time``",,Mark de Wever,|Complete|,17 diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8dac823503d73f..ce805b4eb7b8b4 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -270,6 +270,7 @@ set(files __chrono/steady_clock.h __chrono/sys_info.h __chrono/system_clock.h + __chrono/tai_clock.h __chrono/time_point.h __chrono/time_zone.h __chrono/time_zone_link.h diff --git a/libcxx/include/__chrono/convert_to_tm.h b/libcxx/include/__chrono/convert_to_tm.h index 7d06a38d87f26d..934293ce382345 100644 --- a/libcxx/include/__chrono/convert_to_tm.h +++ b/libcxx/include/__chrono/convert_to_tm.h @@ -23,6 +23,7 @@ #include <__chrono/statically_widen.h> #include <__chrono/sys_info.h> #include <__chrono/system_clock.h> +#include <__chrono/tai_clock.h> #include <__chrono/time_point.h> #include <__chrono/utc_clock.h> #include <__chrono/weekday.h> @@ -112,6 +113,16 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::utc_time<_Duration> __tp) { return __result; } +template +_LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::tai_time<_Duration> __tp) { + using _Rp = common_type_t<_Duration, chrono::seconds>; + // The time between the TAI epoch (1958-01-01) and UNIX epoch (1970-01-01). + // This avoids leap second conversion when going from TAI to UTC. + // (It also avoids issues when the date is before the UTC epoch.) + constexpr chrono::seconds __offset{4383 * 24 * 60 * 60}; + return std::__convert_to_tm<_Tm>(chrono::sys_time<_Rp>{__tp.time_since_epoch() - __offset}); +} + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION @@ -131,6 +142,8 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) { # if _LIBCPP_HAS_EXPERIMENTAL_TZDB else if constexpr (same_as) return std::__convert_to_tm<_Tm>(__value); + else if constexpr (same_as) + return std::__convert_to_tm<_Tm>(__value); # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION else if constexpr (same_as) diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h index d17acd274e4cda..753a824a3c50d7 100644 --- a/libcxx/include/__chrono/formatter.h +++ b/libcxx/include/__chrono/formatter.h @@ -31,6 +31,7 @@ # include <__chrono/statically_widen.h> # include <__chrono/sys_info.h> # include <__chrono/system_clock.h> +# include <__chrono/tai_clock.h> # include <__chrono/time_point.h> # include <__chrono/utc_clock.h> # include <__chrono/weekday.h> @@ -231,6 +232,8 @@ _LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const # if _LIBCPP_HAS_EXPERIMENTAL_TZDB if constexpr (same_as<_Tp, chrono::sys_info>) return {__value.abbrev, __value.offset}; + else if constexpr (__is_time_point<_Tp> && requires { requires same_as; }) + return {"TAI", chrono::seconds{0}}; # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) return __formatter::__convert_to_time_zone(__value.get_info()); @@ -734,6 +737,17 @@ struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : pub } }; +template +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : public __formatter_chrono<_CharT> { +public: + using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); + } +}; + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM diff --git a/libcxx/include/__chrono/ostream.h b/libcxx/include/__chrono/ostream.h index ed9ad8e346ba94..b8cd6a4680662b 100644 --- a/libcxx/include/__chrono/ostream.h +++ b/libcxx/include/__chrono/ostream.h @@ -26,6 +26,7 @@ # include <__chrono/statically_widen.h> # include <__chrono/sys_info.h> # include <__chrono/system_clock.h> +# include <__chrono/tai_clock.h> # include <__chrono/utc_clock.h> # include <__chrono/weekday.h> # include <__chrono/year.h> @@ -71,6 +72,12 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const utc_time<_Duration>& __tp return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); } +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const tai_time<_Duration>& __tp) { + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); +} + # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM diff --git a/libcxx/include/__chrono/tai_clock.h b/libcxx/include/__chrono/tai_clock.h new file mode 100644 index 00000000000000..18ba329b7b8fb4 --- /dev/null +++ b/libcxx/include/__chrono/tai_clock.h @@ -0,0 +1,98 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_TAI_CLOCK_H +#define _LIBCPP___CHRONO_TAI_CLOCK_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if _LIBCPP_HAS_EXPERIMENTAL_TZDB + +# include <__chrono/duration.h> +# include <__chrono/time_point.h> +# include <__chrono/utc_clock.h> +# include <__config> +# include <__type_traits/common_type.h> + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION + +namespace chrono { + +class tai_clock; + +template +using tai_time = time_point; +using tai_seconds = tai_time; + +// [time.clock.tai.overview]/1 +// The clock tai_clock measures seconds since 1958-01-01 00:00:00 and is +// offset 10s ahead of UTC at this date. That is, 1958-01-01 00:00:00 TAI is +// equivalent to 1957-12-31 23:59:50 UTC. Leap seconds are not inserted into +// TAI. Therefore every time a leap second is inserted into UTC, UTC shifts +// another second with respect to TAI. For example by 2000-01-01 there had +// been 22 positive and 0 negative leap seconds inserted so 2000-01-01 +// 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI (22s plus the +// initial 10s offset). +// +// Note this does not specify what the UTC offset before 1958-01-01 00:00:00 +// TAI is. However the member functions are fully specified in the standard. +// https://koka-lang.github.io/koka/doc/std_time_utc.html contains more +// information and references. +class tai_clock { +public: + using rep = utc_clock::rep; + using period = utc_clock::period; + using duration = chrono::duration; + using time_point = chrono::time_point; + static constexpr bool is_steady = false; // The utc_clock is not steady. + + // The static difference between UTC and TAI time. + static constexpr chrono::seconds __offset{378691210}; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static time_point now() { return from_utc(utc_clock::now()); } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static utc_time> + to_utc(const tai_time<_Duration>& __time) noexcept { + using _Rp = common_type_t<_Duration, seconds>; + _Duration __time_since_epoch = __time.time_since_epoch(); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch >= utc_time<_Rp>::min().time_since_epoch() + __offset, + "the TAI to UTC conversion would underflow"); + + return utc_time<_Rp>{__time_since_epoch - __offset}; + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static tai_time> + from_utc(const utc_time<_Duration>& __time) noexcept { + using _Rp = common_type_t<_Duration, seconds>; + _Duration __time_since_epoch = __time.time_since_epoch(); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch <= utc_time<_Rp>::max().time_since_epoch() - __offset, + "the UTC to TAI conversion would overflow"); + + return tai_time<_Rp>{__time_since_epoch + __offset}; + } +}; + +} // namespace chrono + +# endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && + // _LIBCPP_HAS_LOCALIZATION + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB + +#endif // _LIBCPP___CHRONO_TAI_CLOCK_H diff --git a/libcxx/include/chrono b/libcxx/include/chrono index 10695eea649fb7..bd4c98600440c4 100644 --- a/libcxx/include/chrono +++ b/libcxx/include/chrono @@ -335,6 +335,34 @@ struct leap_second_info { // C++20 template // C++20 leap_second_info get_leap_second_info(const utc_time& ut); + +// [time.clock.tai], class tai_clock +class tai_clock { // C++20 +public: + using rep = a signed arithmetic type; + using period = ratio; + using duration = chrono::duration; + using time_point = chrono::time_point; + static constexpr bool is_steady = unspecified; + + static time_point now(); + + template + static utc_time> + to_utc(const tai_time& t); + template + static tai_time> + from_utc(const utc_time& t); +}; + +template +using tai_time = time_point; // C++20 +using tai_seconds = tai_time; // C++20 + +template // C++20 + basic_ostream& + operator<<(basic_ostream& os, const tai_time& t); + class file_clock // C++20 { public: @@ -898,6 +926,8 @@ namespace std { struct formatter, charT>; // C++20 template struct formatter, charT>; // C++20 + template + struct formatter, charT>; // C++20 template struct formatter, charT>; // C++20 template @@ -1014,6 +1044,7 @@ constexpr chrono::year operator ""y(unsigned lo # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION # include <__chrono/leap_second.h> +# include <__chrono/tai_clock.h> # include <__chrono/time_zone.h> # include <__chrono/time_zone_link.h> # include <__chrono/tzdb.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 4bae02137b37b2..fd39c946b992a4 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -967,6 +967,10 @@ module std [system] { header "__chrono/system_clock.h" export std.chrono.time_point } + module tai_clock { + header "__chrono/tai_clock.h" + export std.chrono.time_point + } module time_point { header "__chrono/time_point.h" } module time_zone_link { header "__chrono/time_zone_link.h" } module time_zone { header "__chrono/time_zone.h" } diff --git a/libcxx/modules/std/chrono.inc b/libcxx/modules/std/chrono.inc index 98f14f716c2078..43e8da36e90448 100644 --- a/libcxx/modules/std/chrono.inc +++ b/libcxx/modules/std/chrono.inc @@ -97,13 +97,13 @@ export namespace std { using std::chrono::get_leap_second_info; -# if 0 // [time.clock.tai], class tai_clock using std::chrono::tai_clock; using std::chrono::tai_seconds; using std::chrono::tai_time; +# if 0 // [time.clock.gps], class gps_clock using std::chrono::gps_clock; diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp index 644c5b598c018d..bb40e0cfc4e1b8 100644 --- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp +++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp @@ -102,4 +102,15 @@ void test(std::chrono::time_zone tz, std::chrono::time_zone_link link, std::chro zt.get_sys_time(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} zt.get_info(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} } + + { // [time.clock.tai] + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::now(); + + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::to_utc(std::chrono::tai_seconds{}); + + // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::chrono::tai_clock::from_utc(std::chrono::utc_seconds{}); + } } diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp new file mode 100644 index 00000000000000..3508ceb8b2d3f6 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp @@ -0,0 +1,164 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb +// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME + +// TODO FMT This test should not require std::to_chars(floating-point) +// XFAIL: availability-fp_to_chars-missing + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// REQUIRES: locale.fr_FR.UTF-8 +// REQUIRES: locale.ja_JP.UTF-8 + +// + +// class taitem_clock; + +// template +// basic_ostream& +// operator<<(basic_ostream& os, const tai_time& tp); + +#include +#include +#include +#include + +#include "make_string.h" +#include "platform_support.h" // locale name macros +#include "test_macros.h" + +#define SV(S) MAKE_STRING_VIEW(CharT, S) + +template +static std::basic_string stream_c_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static std::basic_string stream_fr_FR_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + const std::locale locale(LOCALE_fr_FR_UTF_8); + sstr.imbue(locale); + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static std::basic_string stream_ja_JP_locale(std::chrono::tai_time time_point) { + std::basic_stringstream sstr; + const std::locale locale(LOCALE_ja_JP_UTF_8); + sstr.imbue(locale); + sstr << std::fixed << time_point; + return sstr.str(); +} + +template +static void test_c() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + assert(stream_c_locale(cr::tai_time{946'688'523'123'456'789ns}) == + SV("1988-01-01 01:02:03.123456789")); + assert(stream_c_locale(cr::tai_time{946'688'523'123'456us}) == + SV("1988-01-01 01:02:03.123456")); + + assert(stream_c_locale(cr::tai_time{946'684'822'123ms}) == SV("1988-01-01 00:00:22.123")); + assert(stream_c_locale(cr::tai_seconds{1'234'567'890s}) == SV("1997-02-13 23:31:30")); + assert(stream_c_locale(cr::tai_time{20'576'131min}) == SV("1997-02-13 23:31:00")); + assert(stream_c_locale(cr::tai_time{342'935h}) == SV("1997-02-13 23:00:00")); + + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{60}}) == SV("1958-01-01 00:02:00")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:30:00.0")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:15:00.00")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{36611}}) == SV("1958-01-01 01:01:01.1")); + assert(stream_c_locale(cr::tai_time>>{ + cr::duration>{12'345'678'9010}}) == SV("1997-02-13 23:31:30.10")); +} + +template +static void test_fr_FR() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + assert(stream_fr_FR_locale(cr::tai_time{946'688'523'123'456'789ns}) == + SV("1988-01-01 01:02:03,123456789")); + assert(stream_fr_FR_locale(cr::tai_time{946'688'523'123'456us}) == + SV("1988-01-01 01:02:03,123456")); + + assert(stream_fr_FR_locale(cr::tai_time{946'684'822'123ms}) == + SV("1988-01-01 00:00:22,123")); + assert(stream_fr_FR_locale(cr::tai_seconds{1'234'567'890s}) == SV("1997-02-13 23:31:30")); + assert(stream_fr_FR_locale(cr::tai_time{20'576'131min}) == SV("1997-02-13 23:31:00")); + assert(stream_fr_FR_locale(cr::tai_time{342'935h}) == SV("1997-02-13 23:00:00")); + + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{60}}) == SV("1958-01-01 00:02:00")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:30:00,0")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:15:00,00")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{36611}}) == SV("1958-01-01 01:01:01,1")); + assert(stream_fr_FR_locale(cr::tai_time>>{ + cr::duration>{12'345'678'9010}}) == SV("1997-02-13 23:31:30,10")); +} + +template +static void test_ja_JP() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + assert(stream_ja_JP_locale(cr::tai_time{946'688'523'123'456'789ns}) == + SV("1988-01-01 01:02:03.123456789")); + assert(stream_ja_JP_locale(cr::tai_time{946'688'523'123'456us}) == + SV("1988-01-01 01:02:03.123456")); + + assert(stream_ja_JP_locale(cr::tai_time{946'684'822'123ms}) == + SV("1988-01-01 00:00:22.123")); + assert(stream_ja_JP_locale(cr::tai_seconds{1'234'567'890s}) == SV("1997-02-13 23:31:30")); + assert(stream_ja_JP_locale(cr::tai_time{20'576'131min}) == SV("1997-02-13 23:31:00")); + assert(stream_ja_JP_locale(cr::tai_time{342'935h}) == SV("1997-02-13 23:00:00")); + + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{60}}) == SV("1958-01-01 00:02:00")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:30:00.0")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{3600}}) == SV("1958-01-01 00:15:00.00")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{36611}}) == SV("1958-01-01 01:01:01.1")); + assert(stream_ja_JP_locale(cr::tai_time>>{ + cr::duration>{12'345'678'9010}}) == SV("1997-02-13 23:31:30.10")); +} + +template +static void test() { + test_c(); + test_fr_FR(); + test_ja_JP(); +} + +int main(int, char**) { + test(); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + + return 0; +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp new file mode 100644 index 00000000000000..b3ba97bdc49dd9 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp @@ -0,0 +1,159 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// +// +// class tai_clock; + +// static tai_time> +// from_utc(const utc<_Duration>& __time) noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "assert_macros.h" +#include "concat_macros.h" + +static void test_known_values() { + namespace cr = std::chrono; + using namespace std::literals::chrono_literals; + constexpr auto unix_to_tai_epoch_offset = cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + + // [time.clock.tai.overview]/1 + // ... 1958-01-01 00:00:00 TAI is equivalent to 1957-12-31 23:59:50 UTC + // ... 2000-01-01 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI + + assert(cr::tai_clock::from_utc(cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 1958} - 10s)) == + cr::tai_seconds{0s}); + + assert(cr::tai_clock::from_utc(cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 2000})) == + cr::tai_seconds{(cr::sys_days{cr::January / 1 / 2000} + unix_to_tai_epoch_offset).time_since_epoch()} + 32s); +} + +template +static void test_leap_seconds(std::chrono::utc_time utc, + std::chrono::tai_time expected, + std::source_location loc = std::source_location::current()) { + auto tai = std::chrono::tai_clock::from_utc(utc); + TEST_REQUIRE(tai == expected, + TEST_WRITE_CONCATENATED(loc, "\nExpected output ", expected, "\nActual output ", tai, '\n')); +} + +// Tests set if existing database entries at the time of writing. +static void test_transitions() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + // "sys" is the time of the transition to the next leap second. + // "elapsed" is the number of leap seconds before the transition. + auto test_transition = [](cr::sys_days sys, cr::seconds elapsed) { + constexpr auto unix_to_tai_epoch_offset = + cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + cr::tai_seconds tai{sys.time_since_epoch() + unix_to_tai_epoch_offset + elapsed}; + + test_leap_seconds(cr::utc_clock::from_sys(sys - 1ns), tai - 1ns); + test_leap_seconds(cr::utc_clock::from_sys(sys), tai + 1s); + test_leap_seconds(cr::utc_clock::from_sys(sys) + 1ns, tai + 1s + 1ns); + }; + + // Transitions from the start of UTC. + test_transition(cr::sys_days{cr::July / 1 / 1972}, 10s); + test_transition(cr::sys_days{cr::January / 1 / 1973}, 11s); + test_transition(cr::sys_days{cr::January / 1 / 1974}, 12s); + test_transition(cr::sys_days{cr::January / 1 / 1975}, 13s); + test_transition(cr::sys_days{cr::January / 1 / 1976}, 14s); + test_transition(cr::sys_days{cr::January / 1 / 1977}, 15s); + test_transition(cr::sys_days{cr::January / 1 / 1978}, 16s); + test_transition(cr::sys_days{cr::January / 1 / 1979}, 17s); + test_transition(cr::sys_days{cr::January / 1 / 1980}, 18s); + test_transition(cr::sys_days{cr::July / 1 / 1981}, 19s); + test_transition(cr::sys_days{cr::July / 1 / 1982}, 20s); + test_transition(cr::sys_days{cr::July / 1 / 1983}, 21s); + test_transition(cr::sys_days{cr::July / 1 / 1985}, 22s); + test_transition(cr::sys_days{cr::January / 1 / 1988}, 23s); + test_transition(cr::sys_days{cr::January / 1 / 1990}, 24s); + test_transition(cr::sys_days{cr::January / 1 / 1991}, 25s); + test_transition(cr::sys_days{cr::July / 1 / 1992}, 26s); + test_transition(cr::sys_days{cr::July / 1 / 1993}, 27s); + test_transition(cr::sys_days{cr::July / 1 / 1994}, 28s); + test_transition(cr::sys_days{cr::January / 1 / 1996}, 29s); + test_transition(cr::sys_days{cr::July / 1 / 1997}, 30s); + test_transition(cr::sys_days{cr::January / 1 / 1999}, 31s); + test_transition(cr::sys_days{cr::January / 1 / 2006}, 32s); + test_transition(cr::sys_days{cr::January / 1 / 2009}, 33s); + test_transition(cr::sys_days{cr::July / 1 / 2012}, 34s); + test_transition(cr::sys_days{cr::July / 1 / 2015}, 35s); + test_transition(cr::sys_days{cr::January / 1 / 2017}, 36s); +} + +// Tests whether the return type is the expected type. +static void test_return_type() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0ns}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0us}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{0ms}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::seconds{0}}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::minutes{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::hours{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::days{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::weeks{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::months{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::from_utc(cr::utc_time{cr::years{0}}); + } +} + +int main(int, const char**) { + using namespace std::literals::chrono_literals; + std::chrono::utc_seconds time = std::chrono::utc_seconds{0s}; + static_assert(noexcept(std::chrono::tai_clock::from_utc(time))); + + test_known_values(); + test_transitions(); + test_return_type(); +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp new file mode 100644 index 00000000000000..c96ace82daca16 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// +// +// class tai; + +// static time_point now(); + +#include +#include + +int main(int, const char**) { + using clock = std::chrono::tai_clock; + std::same_as decltype(auto) t = clock::now(); + + assert(t >= clock::time_point::min()); + assert(t <= clock::time_point::max()); +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp new file mode 100644 index 00000000000000..210f5b8a125b33 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp @@ -0,0 +1,161 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// +// +// class tai_clock; + +// static utc_time> +// to_utc(const tai_time<_Duration>& __time) noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "assert_macros.h" +#include "concat_macros.h" + +static void test_known_values() { + namespace cr = std::chrono; + using namespace std::literals::chrono_literals; + constexpr auto unix_to_tai_epoch_offset = cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + + // [time.clock.tai.overview]/1 + // ... 1958-01-01 00:00:00 TAI is equivalent to 1957-12-31 23:59:50 UTC + // ... 2000-01-01 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI + + assert(cr::tai_clock::to_utc(cr::tai_seconds{0s}) == + cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 1958} - 10s)); + + assert(cr::tai_clock::to_utc( + cr::tai_seconds{(cr::sys_days{cr::January / 1 / 2000} + unix_to_tai_epoch_offset).time_since_epoch()} + + 32s) == cr::utc_clock::from_sys(cr::sys_days{cr::January / 1 / 2000})); +} + +template +static void test_leap_seconds(std::chrono::tai_time tai, + std::chrono::utc_time expected, + std::source_location loc = std::source_location::current()) { + auto utc = std::chrono::tai_clock::to_utc(tai); + TEST_REQUIRE(utc == expected, + TEST_WRITE_CONCATENATED(loc, "\nExpected output ", expected, "\nActual output ", utc, '\n')); +} + +// Tests set if existing database entries at the time of writing. +static void test_transitions() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + // "sys" is the time of the transition to the next leap second. + // "elapsed" is the number of leap seconds before the transition. + auto test_transition = [](cr::sys_days sys, cr::seconds elapsed) { + constexpr auto unix_to_tai_epoch_offset = + cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 1 / 1958}; + cr::tai_seconds tai{sys.time_since_epoch() + unix_to_tai_epoch_offset + elapsed}; + + test_leap_seconds(tai - 1ns, cr::utc_clock::from_sys(sys - 1ns)); + test_leap_seconds(tai + 1s, cr::utc_clock::from_sys(sys)); + test_leap_seconds(tai + 1s + 1ns, cr::utc_clock::from_sys(sys + 1ns)); + }; + + // Transitions from the start of UTC. + test_transition(cr::sys_days{cr::July / 1 / 1972}, 10s); + test_transition(cr::sys_days{cr::January / 1 / 1973}, 11s); + test_transition(cr::sys_days{cr::January / 1 / 1974}, 12s); + test_transition(cr::sys_days{cr::January / 1 / 1975}, 13s); + test_transition(cr::sys_days{cr::January / 1 / 1976}, 14s); + test_transition(cr::sys_days{cr::January / 1 / 1977}, 15s); + test_transition(cr::sys_days{cr::January / 1 / 1978}, 16s); + test_transition(cr::sys_days{cr::January / 1 / 1979}, 17s); + test_transition(cr::sys_days{cr::January / 1 / 1980}, 18s); + test_transition(cr::sys_days{cr::July / 1 / 1981}, 19s); + test_transition(cr::sys_days{cr::July / 1 / 1982}, 20s); + test_transition(cr::sys_days{cr::July / 1 / 1983}, 21s); + test_transition(cr::sys_days{cr::July / 1 / 1985}, 22s); + test_transition(cr::sys_days{cr::January / 1 / 1988}, 23s); + test_transition(cr::sys_days{cr::January / 1 / 1990}, 24s); + test_transition(cr::sys_days{cr::January / 1 / 1991}, 25s); + test_transition(cr::sys_days{cr::July / 1 / 1992}, 26s); + test_transition(cr::sys_days{cr::July / 1 / 1993}, 27s); + test_transition(cr::sys_days{cr::July / 1 / 1994}, 28s); + test_transition(cr::sys_days{cr::January / 1 / 1996}, 29s); + test_transition(cr::sys_days{cr::July / 1 / 1997}, 30s); + test_transition(cr::sys_days{cr::January / 1 / 1999}, 31s); + test_transition(cr::sys_days{cr::January / 1 / 2006}, 32s); + test_transition(cr::sys_days{cr::January / 1 / 2009}, 33s); + test_transition(cr::sys_days{cr::July / 1 / 2012}, 34s); + test_transition(cr::sys_days{cr::July / 1 / 2015}, 35s); + test_transition(cr::sys_days{cr::January / 1 / 2017}, 36s); +} + +// Tests whether the return type is the expected type. +static void test_return_type() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{0ns}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{0us}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{0ms}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::seconds{0}}); + } + + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::minutes{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::hours{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::days{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::weeks{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::months{0}}); + } + { + [[maybe_unused]] std::same_as> decltype(auto) _ = + cr::tai_clock::to_utc(cr::tai_time{cr::years{0}}); + } +} + +int main(int, const char**) { + using namespace std::literals::chrono_literals; + + std::chrono::tai_seconds time = std::chrono::tai_seconds{0s}; + static_assert(noexcept(std::chrono::tai_clock::to_utc(time))); + + test_known_values(); + test_transitions(); + test_return_type(); +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp new file mode 100644 index 00000000000000..c4af65d447c357 --- /dev/null +++ b/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: availability-tzdb-missing + +// + +// class tai_clock { +// public: +// using rep = a signed arithmetic type; +// using period = ratio; +// using duration = chrono::duration; +// using time_point = chrono::time_point; +// static constexpr bool is_steady = unspecified; +// +// ... +// }; +// +// template +// using tai_time = time_point; +// using tai_seconds = tai_time; + +#include +#include + +#include "test_macros.h" + +// class tai_clock +using rep = std::chrono::tai_clock::rep; +using period = std::chrono::tai_clock::period; +using duration = std::chrono::tai_clock::duration; +using time_point = std::chrono::tai_clock::time_point; +constexpr bool is_steady = std::chrono::tai_clock::is_steady; + +// Tests the values. part of them are implementation defined. +LIBCPP_STATIC_ASSERT(std::same_as); +static_assert(std::is_arithmetic_v); +static_assert(std::is_signed_v); + +LIBCPP_STATIC_ASSERT(std::same_as); +static_assert(std::same_as>); + +static_assert(std::same_as>); +static_assert(std::same_as>); +LIBCPP_STATIC_ASSERT(is_steady == false); + +// typedefs +static_assert(std::same_as, std::chrono::time_point>); +static_assert(std::same_as, std::chrono::time_point>); +static_assert(std::same_as>); diff --git a/libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp b/libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp new file mode 100644 index 00000000000000..7ca088cc6e8f46 --- /dev/null +++ b/libcxx/test/std/time/time.syn/formatter.tai_time.pass.cpp @@ -0,0 +1,998 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb +// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME + +// TODO FMT This test should not require std::to_chars(floating-point) +// XFAIL: availability-fp_to_chars-missing + +// XFAIL: libcpp-has-no-experimental-tzdb +// XFAIL: availability-tzdb-missing + +// REQUIRES: locale.fr_FR.UTF-8 +// REQUIRES: locale.ja_JP.UTF-8 + +// + +// template +// struct formatter, charT>; + +#include +#include + +#include +#include +#include +#include +#include + +#include "formatter_tests.h" +#include "make_string.h" +#include "platform_support.h" // locale name macros +#include "test_macros.h" + +template +static void test_no_chrono_specs() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output + + // [time.syn] + // using nanoseconds = duration; + // using microseconds = duration; + // using milliseconds = duration; + // using seconds = duration; + // using minutes = duration>; + // using hours = duration>; + check(SV("1413-08-04 22:06:56"), SV("{}"), cr::tai_seconds(-17'179'869'184s)); // Minimum value for 35 bits. + check(SV("1889-12-12 20:45:52"), SV("{}"), cr::tai_seconds(-2'147'483'648s)); + + check(SV("1957-12-31 00:00:00"), SV("{}"), cr::tai_seconds(-24h)); + check(SV("1957-12-31 06:00:00"), SV("{}"), cr::tai_seconds(-18h)); + check(SV("1957-12-31 12:00:00"), SV("{}"), cr::tai_seconds(-12h)); + check(SV("1957-12-31 18:00:00"), SV("{}"), cr::tai_seconds(-6h)); + check(SV("1957-12-31 23:59:59"), SV("{}"), cr::tai_seconds(-1s)); + + check(SV("1958-01-01 00:00:00"), SV("{}"), cr::tai_seconds(0s)); + check(SV("1988-01-01 00:00:00"), SV("{}"), cr::tai_seconds(946'684'800s)); + check(SV("1988-01-01 01:02:03"), SV("{}"), cr::tai_seconds(946'688'523s)); + + check(SV("2026-01-19 03:14:07"), SV("{}"), cr::tai_seconds(2'147'483'647s)); + check(SV("2502-05-30 01:53:03"), SV("{}"), cr::tai_seconds(17'179'869'183s)); // Maximum value for 35 bits. + + check(SV("1988-01-01 01:02:03.123"), SV("{}"), cr::tai_time(946'688'523'123ms)); + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_year() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = + SV("{:%%C='%C'%t%%EC='%EC'%t%%y='%y'%t%%Oy='%Oy'%t%%Ey='%Ey'%t%%Y='%Y'%t%%EY='%EY'%n}"); + constexpr std::basic_string_view lfmt = + SV("{:L%%C='%C'%t%%EC='%EC'%t%%y='%y'%t%%Oy='%Oy'%t%%Ey='%Ey'%t%%Y='%Y'%t%%EY='%EY'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%C='19'\t%EC='19'\t%y='58'\t%Oy='58'\t%Ey='58'\t%Y='1958'\t%EY='1958'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%C='20'\t%EC='20'\t%y='09'\t%Oy='09'\t%Ey='09'\t%Y='2009'\t%EY='2009'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%C='19'\t%EC='19'\t%y='58'\t%Oy='58'\t%Ey='58'\t%Y='1958'\t%EY='1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%C='20'\t%EC='20'\t%y='09'\t%Oy='09'\t%Ey='09'\t%Y='2009'\t%EY='2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%C='19'\t%EC='19'\t%y='58'\t%Oy='58'\t%Ey='58'\t%Y='1958'\t%EY='1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%C='20'\t%EC='20'\t%y='09'\t%Oy='09'\t%Ey='09'\t%Y='2009'\t%EY='2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX)||defined(__FreeBSD__) + check(loc, + SV("%C='19'\t%EC='昭和'\t%y='58'\t%Oy='五十八'\t%Ey='33'\t%Y='1958'\t%EY='昭和33年'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%C='20'\t%EC='平成'\t%y='09'\t%Oy='九'\t%Ey='21'\t%Y='2009'\t%EY='平成21年'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX)||defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_month() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%b='%b'%t%%h='%h'%t%%B='%B'%t%%m='%m'%t%%Om='%Om'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%b='%b'%t%%h='%h'%t%%B='%B'%t%%m='%m'%t%%Om='%Om'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%b='Jan'\t%h='Jan'\t%B='January'\t%m='01'\t%Om='01'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%b='May'\t%h='May'\t%B='May'\t%m='05'\t%Om='05'\n"), + fmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI on Wednesday, 18 May 2033 + + // Use the global locale (fr_FR) +#if defined(__APPLE__) + check(SV("%b='jan'\t%h='jan'\t%B='janvier'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 +#else + check(SV("%b='janv.'\t%h='janv.'\t%B='janvier'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 +#endif + + check(SV("%b='mai'\t%h='mai'\t%B='mai'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI on Wednesday, 18 May 2033 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#ifdef _WIN32 + check(loc, + SV("%b='1'\t%h='1'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b='5'\t%h='5'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#elif defined(_AIX) // _WIN32 + check(loc, + SV("%b='1月'\t%h='1月'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b='5月'\t%h='5月'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#elif defined(__APPLE__) // _WIN32 + check(loc, + SV("%b=' 1'\t%h=' 1'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b=' 5'\t%h=' 5'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#elif defined(__FreeBSD__) // _WIN32 + check(loc, + SV("%b=' 1月'\t%h=' 1月'\t%B='1月'\t%m='01'\t%Om='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b=' 5月'\t%h=' 5月'\t%B='5月'\t%m='05'\t%Om='05'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#else // _WIN32 + check(loc, + SV("%b=' 1月'\t%h=' 1月'\t%B='1月'\t%m='01'\t%Om='一'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%b=' 5月'\t%h=' 5月'\t%B='5月'\t%m='05'\t%Om='五'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#endif // _WIN32 + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_day() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%d='%d'%t%%Od='%Od'%t%%e='%e'%t%%Oe='%Oe'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%d='%d'%t%%Od='%Od'%t%%e='%e'%t%%Oe='%Oe'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%d='13'\t%Od='13'\t%e='13'\t%Oe='13'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%d='13'\t%Od='13'\t%e='13'\t%Oe='13'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%d='13'\t%Od='13'\t%e='13'\t%Oe='13'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%d='01'\t%Od='01'\t%e=' 1'\t%Oe=' 1'\n"), + lfmt, +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%d='01'\t%Od='一'\t%e=' 1'\t%Oe='一'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%d='13'\t%Od='十三'\t%e='13'\t%Oe='十三'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_weekday() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = + SV("{:%%a='%a'%t%%A='%A'%t%%u='%u'%t%%Ou='%Ou'%t%%w='%w'%t%%Ow='%Ow'%n}"); + constexpr std::basic_string_view lfmt = + SV("{:L%%a='%a'%t%%A='%A'%t%%u='%u'%t%%Ou='%Ou'%t%%w='%w'%t%%Ow='%Ow'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%a='Wed'\t%A='Wednesday'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%a='Sun'\t%A='Sunday'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + fmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 + + // Use the global locale (fr_FR) +#if defined(__APPLE__) + check(SV("%a='mer'\t%A='Mercredi'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%a='Dim'\t%A='Dimanche'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#else + check(SV("%a='mer.'\t%A='mercredi'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%a='dim.'\t%A='dimanche'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#endif + + // Use supplied locale (ja_JP). + // This locale has a different alternate, but not on all platforms +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%a='水'\t%A='水曜日'\t%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%a='日'\t%A='日曜日'\t%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%a='水'\t%A='水曜日'\t%u='3'\t%Ou='三'\t%w='3'\t%Ow='三'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%a='日'\t%A='日曜日'\t%u='7'\t%Ou='七'\t%w='0'\t%Ow='〇'\n"), + lfmt, + cr::tai_seconds(4'673'658'495s)); // 06:28:15 TAI on Sunday, 7 February 2106 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_day_of_year() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%j='%j'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%j='%j'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%j='001'\n"), fmt, cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(SV("%j='138'\n"), fmt, cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use the global locale (fr_FR) + check(SV("%j='001'\n"), lfmt, cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(SV("%j='138'\n"), lfmt, cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use supplied locale (ja_JP). This locale has a different alternate. + check(loc, SV("%j='001'\n"), lfmt, cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, SV("%j='138'\n"), lfmt, cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_week() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%U='%U'%t%%OU='%OU'%t%%W='%W'%t%%OW='%OW'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%U='%U'%t%%OU='%OU'%t%%W='%W'%t%%OW='%OW'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%U='00'\t%OU='00'\t%W='00'\t%OW='00'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%U='20'\t%OU='20'\t%W='20'\t%OW='20'\n"), + fmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use the global locale (fr_FR) + check(SV("%U='00'\t%OU='00'\t%W='00'\t%OW='00'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%U='20'\t%OU='20'\t%W='20'\t%OW='20'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%U='00'\t%OU='00'\t%W='00'\t%OW='00'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%U='20'\t%OU='20'\t%W='20'\t%OW='20'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%U='00'\t%OU='〇'\t%W='00'\t%OW='〇'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%U='20'\t%OU='二十'\t%W='20'\t%OW='二十'\n"), + lfmt, + cr::tai_seconds(2'378'691'200s)); // 03:33:20 TAI Wednesday, 18 May 2033 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_iso_8601_week() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%g='%g'%t%%G='%G'%t%%V='%V'%t%%OV='%OV'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%g='%g'%t%%G='%G'%t%%V='%V'%t%%OV='%OV'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%g='58'\t%G='1958'\t%V='01'\t%OV='01'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%g='09'\t%G='2009'\t%V='07'\t%OV='07'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check(SV("%g='58'\t%G='1958'\t%V='01'\t%OV='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%g='09'\t%G='2009'\t%V='07'\t%OV='07'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%g='58'\t%G='1958'\t%V='01'\t%OV='01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%g='09'\t%G='2009'\t%V='07'\t%OV='07'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%g='58'\t%G='1958'\t%V='01'\t%OV='一'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%g='09'\t%G='2009'\t%V='07'\t%OV='七'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_date() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%D='%D'%t%%F='%F'%t%%x='%x'%t%%Ex='%Ex'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%D='%D'%t%%F='%F'%t%%x='%x'%t%%Ex='%Ex'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%D='01/01/58'\t%F='1958-01-01'\t%x='01/01/58'\t%Ex='01/01/58'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%D='02/13/09'\t%F='2009-02-13'\t%x='02/13/09'\t%Ex='02/13/09'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) +#if defined(__APPLE__) || defined(__FreeBSD__) + check(SV("%D='01/01/58'\t%F='1958-01-01'\t%x='01.01.1958'\t%Ex='01.01.1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%D='02/13/09'\t%F='2009-02-13'\t%x='13.02.2009'\t%Ex='13.02.2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else + check(SV("%D='01/01/58'\t%F='1958-01-01'\t%x='01/01/1958'\t%Ex='01/01/1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%D='02/13/09'\t%F='2009-02-13'\t%x='13/02/2009'\t%Ex='13/02/2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%D='01/01/58'\t%F='1958-01-01'\t%x='1958/01/01'\t%Ex='1958/01/01'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%D='02/13/09'\t%F='2009-02-13'\t%x='2009/02/13'\t%Ex='2009/02/13'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + check(loc, + SV("%D='01/01/58'\t%F='1958-01-01'\t%x='1958年01月01日'\t%Ex='昭和33年01月01日'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%D='02/13/09'\t%F='2009-02-13'\t%x='2009年02月13日'\t%Ex='平成21年02月13日'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(_WIN32) || defined(__APPLE__) || defined(_AIX) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_time() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV( + "{:" + "%%H='%H'%t" + "%%OH='%OH'%t" + "%%I='%I'%t" + "%%OI='%OI'%t" + "%%M='%M'%t" + "%%OM='%OM'%t" + "%%S='%S'%t" + "%%OS='%OS'%t" + "%%p='%p'%t" + "%%R='%R'%t" + "%%T='%T'%t" + "%%r='%r'%t" + "%%X='%X'%t" + "%%EX='%EX'%t" + "%n}"); + constexpr std::basic_string_view lfmt = SV( + "{:L" + "%%H='%H'%t" + "%%OH='%OH'%t" + "%%I='%I'%t" + "%%OI='%OI'%t" + "%%M='%M'%t" + "%%OM='%OM'%t" + "%%S='%S'%t" + "%%OS='%OS'%t" + "%%p='%p'%t" + "%%R='%R'%t" + "%%T='%T'%t" + "%%r='%r'%t" + "%%X='%X'%t" + "%%EX='%EX'%t" + "%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%H='00'\t" + "%OH='00'\t" + "%I='12'\t" + "%OI='12'\t" + "%M='00'\t" + "%OM='00'\t" + "%S='00'\t" + "%OS='00'\t" + "%p='AM'\t" + "%R='00:00'\t" + "%T='00:00:00'\t" + "%r='12:00:00 AM'\t" + "%X='00:00:00'\t" + "%EX='00:00:00'\t" + "\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%H='23'\t" + "%OH='23'\t" + "%I='11'\t" + "%OI='11'\t" + "%M='31'\t" + "%OM='31'\t" + "%S='30.123'\t" + "%OS='30.123'\t" + "%p='PM'\t" + "%R='23:31'\t" + "%T='23:31:30.123'\t" + "%r='11:31:30 PM'\t" + "%X='23:31:30'\t" + "%EX='23:31:30'\t" + "\n"), + fmt, + cr::tai_time(1'613'259'090'123ms)); // 23:31:30 TAI Friday, 13 February 2009 + // Use the global locale (fr_FR) + check(SV("%H='00'\t" + "%OH='00'\t" + "%I='12'\t" + "%OI='12'\t" + "%M='00'\t" + "%OM='00'\t" + "%S='00'\t" + "%OS='00'\t" +#if defined(_AIX) + "%p='AM'\t" +#else + "%p=''\t" +#endif + "%R='00:00'\t" + "%T='00:00:00'\t" +#ifdef _WIN32 + "%r='00:00:00'\t" +#elif defined(_AIX) + "%r='12:00:00 AM'\t" +#elif defined(__APPLE__) || defined(__FreeBSD__) + "%r=''\t" +#else + "%r='12:00:00 '\t" +#endif + "%X='00:00:00'\t" + "%EX='00:00:00'\t" + "\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%H='23'\t" + "%OH='23'\t" + "%I='11'\t" + "%OI='11'\t" + "%M='31'\t" + "%OM='31'\t" + "%S='30,123'\t" + "%OS='30,123'\t" +#if defined(_AIX) + "%p='PM'\t" +#else + "%p=''\t" +#endif + "%R='23:31'\t" + "%T='23:31:30,123'\t" +#ifdef _WIN32 + "%r='23:31:30'\t" +#elif defined(_AIX) + "%r='11:31:30 PM'\t" +#elif defined(__APPLE__) || defined(__FreeBSD__) + "%r=''\t" +#else + "%r='11:31:30 '\t" +#endif + "%X='23:31:30'\t" + "%EX='23:31:30'\t" + "\n"), + lfmt, + cr::tai_time(1'613'259'090'123ms)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate. +#if defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) + check(loc, + SV("%H='00'\t" + "%OH='00'\t" + "%I='12'\t" + "%OI='12'\t" + "%M='00'\t" + "%OM='00'\t" + "%S='00'\t" + "%OS='00'\t" +# if defined(__APPLE__) + "%p='AM'\t" +# else + "%p='午前'\t" +# endif + "%R='00:00'\t" + "%T='00:00:00'\t" +# if defined(__APPLE__) || defined(__FreeBSD__) +# if defined(__APPLE__) + "%r='12:00:00 AM'\t" +# else + "%r='12:00:00 午前'\t" +# endif + "%X='00時00分00秒'\t" + "%EX='00時00分00秒'\t" +# elif defined(_WIN32) + "%r='0:00:00'\t" + "%X='0:00:00'\t" + "%EX='0:00:00'\t" +# else + "%r='午前12:00:00'\t" + "%X='00:00:00'\t" + "%EX='00:00:00'\t" +# endif + "\n"), + lfmt, + cr::hh_mm_ss(0s)); + + check(loc, + SV("%H='23'\t" + "%OH='23'\t" + "%I='11'\t" + "%OI='11'\t" + "%M='31'\t" + "%OM='31'\t" + "%S='30.123'\t" + "%OS='30.123'\t" +# if defined(__APPLE__) + "%p='PM'\t" +# else + "%p='午後'\t" +# endif + "%R='23:31'\t" + "%T='23:31:30.123'\t" +# if defined(__APPLE__) || defined(__FreeBSD__) +# if defined(__APPLE__) + "%r='11:31:30 PM'\t" +# else + "%r='11:31:30 午後'\t" +# endif + "%X='23時31分30秒'\t" + "%EX='23時31分30秒'\t" +# elif defined(_WIN32) + "%r='23:31:30'\t" + "%X='23:31:30'\t" + "%EX='23:31:30'\t" +# else + "%r='午後11:31:30'\t" + "%X='23:31:30'\t" + "%EX='23:31:30'\t" +# endif + "\n"), + lfmt, + cr::hh_mm_ss(23h + 31min + 30s + 123ms)); +#else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) + check(loc, + SV("%H='00'\t" + "%OH='〇'\t" + "%I='12'\t" + "%OI='十二'\t" + "%M='00'\t" + "%OM='〇'\t" + "%S='00'\t" + "%OS='〇'\t" + "%p='午前'\t" + "%R='00:00'\t" + "%T='00:00:00'\t" + "%r='午前12時00分00秒'\t" + "%X='00時00分00秒'\t" + "%EX='00時00分00秒'\t" + "\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%H='23'\t" + "%OH='二十三'\t" + "%I='11'\t" + "%OI='十一'\t" + "%M='31'\t" + "%OM='三十一'\t" + "%S='30.123'\t" + "%OS='三十.123'\t" + "%p='午後'\t" + "%R='23:31'\t" + "%T='23:31:30.123'\t" + "%r='午後11時31分30秒'\t" + "%X='23時31分30秒'\t" + "%EX='23時31分30秒'\t" + "\n"), + lfmt, + cr::tai_time(1'613'259'090'123ms)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_date_time() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%c='%c'%t%%Ec='%Ec'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%c='%c'%t%%Ec='%Ec'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%c='Wed Jan 1 00:00:00 1958'\t%Ec='Wed Jan 1 00:00:00 1958'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(SV("%c='Fri Feb 13 23:31:30 2009'\t%Ec='Fri Feb 13 23:31:30 2009'\n"), + fmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use the global locale (fr_FR) + check( +// https://sourceware.org/bugzilla/show_bug.cgi?id=24054 +#if defined(__powerpc__) && defined(__linux__) + SV("%c='mer. 01 janv. 1958 00:00:00 TAI'\t%Ec='mer. 01 janv. 1958 00:00:00 TAI'\n"), +#elif defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29 + SV("%c='mer. 01 janv. 1958 00:00:00 GMT'\t%Ec='mer. 01 janv. 1958 00:00:00 GMT'\n"), +#elif defined(_AIX) + SV("%c=' 1 janvier 1958 à 00:00:00 TAI'\t%Ec=' 1 janvier 1958 à 00:00:00 TAI'\n"), +#elif defined(__APPLE__) + SV("%c='Jeu 1 jan 00:00:00 1958'\t%Ec='Jeu 1 jan 00:00:00 1958'\n"), +#elif defined(_WIN32) + SV("%c='01/01/1958 00:00:00'\t%Ec='01/01/1958 00:00:00'\n"), +#elif defined(__FreeBSD__) + SV("%c='mer. 1 janv. 00:00:00 1958'\t%Ec='mer. 1 janv. 00:00:00 1958'\n"), +#else + SV("%c='mer. 01 janv. 1958 00:00:00'\t%Ec='mer. 01 janv. 1958 00:00:00'\n"), +#endif + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check( +// https://sourceware.org/bugzilla/show_bug.cgi?id=24054 +#if defined(__powerpc__) && defined(__linux__) + SV("%c='ven. 13 févr. 2009 23:31:30 TAI'\t%Ec='ven. 13 févr. 2009 23:31:30 TAI'\n"), +#elif defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29 + SV("%c='ven. 13 févr. 2009 23:31:30 GMT'\t%Ec='ven. 13 févr. 2009 23:31:30 GMT'\n"), +#elif defined(_AIX) + SV("%c='13 février 2009 à 23:31:30 TAI'\t%Ec='13 février 2009 à 23:31:30 TAI'\n"), +#elif defined(__APPLE__) + SV("%c='Ven 13 fév 23:31:30 2009'\t%Ec='Ven 13 fév 23:31:30 2009'\n"), +#elif defined(_WIN32) + SV("%c='13/02/2009 23:31:30'\t%Ec='13/02/2009 23:31:30'\n"), +#elif defined(__FreeBSD__) + SV("%c='ven. 13 févr. 23:31:30 2009'\t%Ec='ven. 13 févr. 23:31:30 2009'\n"), +#else + SV("%c='ven. 13 févr. 2009 23:31:30'\t%Ec='ven. 13 févr. 2009 23:31:30'\n"), +#endif + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 + + // Use supplied locale (ja_JP). This locale has a different alternate.a +#if defined(__APPLE__) || defined(__FreeBSD__) + check(loc, + SV("%c='水 1/ 1 00:00:00 1958'\t%Ec='水 1/ 1 00:00:00 1958'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, + SV("%c='金 2/13 23:31:30 2009'\t%Ec='金 2/13 23:31:30 2009'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#elif defined(_AIX) // defined(__APPLE__)|| defined(__FreeBSD__) + check(loc, + SV("%c='1958年01月 1日 00:00:00 TAI'\t%Ec='1958年01月 1日 00:00:00 TAI'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, + SV("%c='2009年02月13日 23:31:30 TAI'\t%Ec='2009年02月13日 23:31:30 TAI'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#elif defined(_WIN32) // defined(__APPLE__)|| defined(__FreeBSD__) + check(loc, + SV("%c='1958/01/01 0:00:00'\t%Ec='1958/01/01 0:00:00'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + check(loc, + SV("%c='2009/02/13 23:31:30'\t%Ec='2009/02/13 23:31:30'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#else // defined(__APPLE__)|| defined(__FreeBSD__) + check(loc, + SV("%c='1958年01月01日 00時00分00秒'\t%Ec='昭和33年01月01日 00時00分00秒'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + check(loc, + SV("%c='2009年02月13日 23時31分30秒'\t%Ec='平成21年02月13日 23時31分30秒'\n"), + lfmt, + cr::tai_seconds(1'613'259'090s)); // 23:31:30 TAI Friday, 13 February 2009 +#endif // defined(__APPLE__)|| defined(__FreeBSD__) + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values_time_zone() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + constexpr std::basic_string_view fmt = SV("{:%%z='%z'%t%%Ez='%Ez'%t%%Oz='%Oz'%t%%Z='%Z'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%z='%z'%t%%Ez='%Ez'%t%%Oz='%Oz'%t%%Z='%Z'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='TAI'\n"), + fmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + // Use the global locale (fr_FR) + check(SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='TAI'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + // Use supplied locale (ja_JP). + check(loc, + SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='TAI'\n"), + lfmt, + cr::tai_seconds(0s)); // 00:00:00 TAI Wednesday, 1 January 1958 + + std::locale::global(std::locale::classic()); +} + +template +static void test_valid_values() { + test_valid_values_year(); + test_valid_values_month(); + test_valid_values_day(); + test_valid_values_weekday(); + test_valid_values_day_of_year(); + test_valid_values_week(); + test_valid_values_iso_8601_week(); + test_valid_values_date(); + test_valid_values_time(); + test_valid_values_date_time(); + test_valid_values_time_zone(); +} + +template +static void test() { + using namespace std::literals::chrono_literals; + namespace cr = std::chrono; + + test_no_chrono_specs(); + test_valid_values(); + check_invalid_types( + {SV("a"), SV("A"), SV("b"), SV("B"), SV("c"), SV("C"), SV("d"), SV("D"), SV("e"), SV("F"), SV("g"), + SV("G"), SV("h"), SV("H"), SV("I"), SV("j"), SV("m"), SV("M"), SV("p"), SV("r"), SV("R"), SV("S"), + SV("T"), SV("u"), SV("U"), SV("V"), SV("w"), SV("W"), SV("x"), SV("X"), SV("y"), SV("Y"), SV("z"), + SV("Z"), SV("Ec"), SV("EC"), SV("Ex"), SV("EX"), SV("Ey"), SV("EY"), SV("Ez"), SV("Od"), SV("Oe"), SV("OH"), + SV("OI"), SV("Om"), SV("OM"), SV("OS"), SV("Ou"), SV("OU"), SV("OV"), SV("Ow"), SV("OW"), SV("Oy"), SV("Oz")}, + cr::tai_seconds(0s)); + + check_exception("The format specifier expects a '%' or a '}'", SV("{:A"), cr::tai_seconds(0s)); + check_exception("The chrono specifiers contain a '{'", SV("{:%%{"), cr::tai_seconds(0s)); + check_exception("End of input while parsing a conversion specifier", SV("{:%"), cr::tai_seconds(0s)); + check_exception("End of input while parsing the modifier E", SV("{:%E"), cr::tai_seconds(0s)); + check_exception("End of input while parsing the modifier O", SV("{:%O"), cr::tai_seconds(0s)); + + // Precision not allowed + check_exception("The format specifier expects a '%' or a '}'", SV("{:.3}"), cr::tai_seconds(0s)); +} + +int main(int, char**) { + test(); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + + return 0; +} diff --git a/libcxx/test/support/concat_macros.h b/libcxx/test/support/concat_macros.h index d7340b8faf6e56..50b65621973927 100644 --- a/libcxx/test/support/concat_macros.h +++ b/libcxx/test/support/concat_macros.h @@ -11,6 +11,7 @@ #include #include +#include #include "assert_macros.h" #include "test_macros.h" @@ -134,6 +135,10 @@ OutIt test_transcode(InIt first, InIt last, OutIt out_it) { return out_it; } +std::ostream& operator<<(std::ostream& os, const std::source_location& loc) { + return os << loc.file_name() << ':' << loc.line() << ':' << loc.column(); +} + template concept test_streamable = requires(std::stringstream& stream, T&& value) { stream << value; }; >From 71536e015e10b5c878e9e7562bf6e7bf4981150a Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Mon, 3 Feb 2025 20:40:16 +0100 Subject: [PATCH 2/5] CI fixes --- libcxx/include/__chrono/convert_to_tm.h | 1 + libcxx/include/__chrono/formatter.h | 4 ++-- libcxx/include/__chrono/tai_clock.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__chrono/convert_to_tm.h b/libcxx/include/__chrono/convert_to_tm.h index 934293ce382345..d9ccf693160d29 100644 --- a/libcxx/include/__chrono/convert_to_tm.h +++ b/libcxx/include/__chrono/convert_to_tm.h @@ -36,6 +36,7 @@ #include <__config> #include <__format/format_error.h> #include <__memory/addressof.h> +#include <__type_traits/common_type.h> #include <__type_traits/is_convertible.h> #include <__type_traits/is_specialization.h> #include diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h index 753a824a3c50d7..13bcb717291f69 100644 --- a/libcxx/include/__chrono/formatter.h +++ b/libcxx/include/__chrono/formatter.h @@ -232,12 +232,12 @@ _LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const # if _LIBCPP_HAS_EXPERIMENTAL_TZDB if constexpr (same_as<_Tp, chrono::sys_info>) return {__value.abbrev, __value.offset}; +# if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM else if constexpr (__is_time_point<_Tp> && requires { requires same_as; }) return {"TAI", chrono::seconds{0}}; -# if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) return __formatter::__convert_to_time_zone(__value.get_info()); -# endif +# endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM else # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB return {"UTC", chrono::seconds{0}}; diff --git a/libcxx/include/__chrono/tai_clock.h b/libcxx/include/__chrono/tai_clock.h index 18ba329b7b8fb4..17c637d2b2c8c8 100644 --- a/libcxx/include/__chrono/tai_clock.h +++ b/libcxx/include/__chrono/tai_clock.h @@ -14,6 +14,7 @@ // Enable the contents of the header only when libc++ was built with experimental features enabled. #if _LIBCPP_HAS_EXPERIMENTAL_TZDB +# include <__assert> # include <__chrono/duration.h> # include <__chrono/time_point.h> # include <__chrono/utc_clock.h> >From de82e4524df6a3c07434fefd9d831f18905f9181 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Mon, 3 Feb 2025 21:06:37 +0100 Subject: [PATCH 3/5] CI fixes. --- .../time.clock.tai/time.clock.tai.members/now.pass.cpp | 1 + .../std/time/time.clock/time.clock.tai/types.compile.pass.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp index c96ace82daca16..b44f48f1eb8f31 100644 --- a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp @@ -19,6 +19,7 @@ // static time_point now(); #include +#include #include int main(int, const char**) { diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp index c4af65d447c357..0df21e6d858723 100644 --- a/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp +++ b/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp @@ -29,8 +29,9 @@ // using tai_time = time_point; // using tai_seconds = tai_time; -#include #include +#include +#include #include "test_macros.h" >From 6f521f1f28dd684ec5fc54cc41703def207115ed Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Tue, 4 Feb 2025 18:26:42 +0100 Subject: [PATCH 4/5] Addresses review comments. --- libcxx/include/__chrono/tai_clock.h | 6 +++++- .../time.clock/time.clock.tai/tai_time.ostream.pass.cpp | 2 +- .../time.clock.tai/time.clock.tai.members/from_utc.pass.cpp | 2 ++ .../time.clock.tai/time.clock.tai.members/now.pass.cpp | 2 ++ .../time.clock.tai/time.clock.tai.members/to_utc.pass.cpp | 2 ++ 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__chrono/tai_clock.h b/libcxx/include/__chrono/tai_clock.h index 17c637d2b2c8c8..ab07ded4883447 100644 --- a/libcxx/include/__chrono/tai_clock.h +++ b/libcxx/include/__chrono/tai_clock.h @@ -48,7 +48,11 @@ using tai_seconds = tai_time; // initial 10s offset). // // Note this does not specify what the UTC offset before 1958-01-01 00:00:00 -// TAI is. However the member functions are fully specified in the standard. +// TAI is, nor does it follow the "real" TAI clock between 1958-01-01 and the +// start of the UTC epoch. So while the member functions are fully specified in +// the standard, they do not technically follow the "real-world" TAI clock with +// 100% accuracy. +// // https://koka-lang.github.io/koka/doc/std_time_utc.html contains more // information and references. class tai_clock { diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp index 3508ceb8b2d3f6..3407fb27c66928 100644 --- a/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp +++ b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp @@ -21,7 +21,7 @@ // -// class taitem_clock; +// class tai_clock; // template // basic_ostream& diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp index b3ba97bdc49dd9..807d3f3120b72a 100644 --- a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp @@ -156,4 +156,6 @@ int main(int, const char**) { test_known_values(); test_transitions(); test_return_type(); + + return 0; } diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp index b44f48f1eb8f31..83736380f293b6 100644 --- a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp @@ -28,4 +28,6 @@ int main(int, const char**) { assert(t >= clock::time_point::min()); assert(t <= clock::time_point::max()); + + return 0; } diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp index 210f5b8a125b33..e8d95737161108 100644 --- a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp @@ -158,4 +158,6 @@ int main(int, const char**) { test_known_values(); test_transitions(); test_return_type(); + + return 0; } >From 0858a050599194fa86b2b2ee7d1e78d267ec33f8 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Tue, 4 Feb 2025 20:47:27 +0100 Subject: [PATCH 5/5] Fixes CI issues and adds missing tests. --- libcxx/docs/Status/FormatPaper.csv | 2 +- libcxx/include/__chrono/tai_clock.h | 5 ++ .../assert.from_utc.pass.cpp | 73 +++++++++++++++++++ .../assert.to_utc.pass.cpp | 73 +++++++++++++++++++ .../time.clock.tai/tai_time.ostream.pass.cpp | 2 +- .../time.clock.tai.members/from_utc.pass.cpp | 2 +- .../time.clock.tai.members/now.pass.cpp | 2 +- .../time.clock.tai.members/to_utc.pass.cpp | 2 +- .../time.clock.tai/types.compile.pass.cpp | 2 +- 9 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 libcxx/test/libcxx/time/time.clock/time.clock.tai/time.clock.tai.members/assert.from_utc.pass.cpp create mode 100644 libcxx/test/libcxx/time/time.clock/time.clock.tai/time.clock.tai.members/assert.to_utc.pass.cpp diff --git a/libcxx/docs/Status/FormatPaper.csv b/libcxx/docs/Status/FormatPaper.csv index de64e9c25a7771..beec97b8c01790 100644 --- a/libcxx/docs/Status/FormatPaper.csv +++ b/libcxx/docs/Status/FormatPaper.csv @@ -3,7 +3,7 @@ Section,Description,Dependencies,Assignee,Status,First released version `[time.syn] `_,"Formatter ``chrono::duration``",,Mark de Wever,|Complete|,16 `[time.syn] `_,"Formatter ``chrono::sys_time``",,Mark de Wever,|Complete|,17 `[time.syn] `_,"Formatter ``chrono::utc_time``",A ```` implementation,Mark de Wever,|Complete|,20 -+`[time.syn] `_,"Formatter ``chrono::tai_time``",,Mark de Wever,|Complete|,21 +`[time.syn] `_,"Formatter ``chrono::tai_time``",,Mark de Wever,|Complete|,21 `[time.syn] `_,"Formatter ``chrono::gps_time``",A ```` implementation,Mark de Wever,,, `[time.syn] `_,"Formatter ``chrono::file_time``",,Mark de Wever,|Complete|,17 `[time.syn] `_,"Formatter ``chrono::local_time``",,Mark de Wever,|Complete|,17 diff --git a/libcxx/include/__chrono/tai_clock.h b/libcxx/include/__chrono/tai_clock.h index ab07ded4883447..14c8b70a94af5f 100644 --- a/libcxx/include/__chrono/tai_clock.h +++ b/libcxx/include/__chrono/tai_clock.h @@ -25,6 +25,9 @@ # pragma GCC system_header # endif +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD # if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION @@ -98,6 +101,8 @@ class tai_clock { _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB #endif // _LIBCPP___CHRONO_TAI_CLOCK_H diff --git a/libcxx/test/libcxx/time/time.clock/time.clock.tai/time.clock.tai.members/assert.from_utc.pass.cpp b/libcxx/test/libcxx/time/time.clock/time.clock.tai/time.clock.tai.members/assert.from_utc.pass.cpp new file mode 100644 index 00000000000000..4d4c35b21a6a36 --- /dev/null +++ b/libcxx/test/libcxx/time/time.clock/time.clock.tai/time.clock.tai.members/assert.from_utc.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-experimental-tzdb +// XFAIL: availability-tzdb-missing + +// REQUIRES: has-unix-headers +// UNSUPPORTED: libcpp-hardening-mode=none +// XFAIL: libcpp-hardening-mode=fast && availability-verbose_abort-missing + +// +// +// class tai_clock; + +// static tai_time> +// from_utc(const utc_time<_Duration>& t) noexcept; + +#include + +#include "check_assertion.h" + +// The function is specified as +// tai_time>{t.time_since_epoch()} + 378691210s +// When t == t.max() there will be a signed integral overflow (other values too). +int main(int, char**) { + using namespace std::literals::chrono_literals; + constexpr std::chrono::seconds offset{378691210}; + + (void)std::chrono::tai_clock::from_utc(std::chrono::utc_time::max() - offset); + TEST_LIBCPP_ASSERT_FAILURE( + std::chrono::tai_clock::from_utc(std::chrono::utc_time::max() - offset + 1ns), + "the UTC to TAI conversion would overflow"); + + (void)std::chrono::tai_clock::from_utc(std::chrono::utc_time::max() - offset); + TEST_LIBCPP_ASSERT_FAILURE( + std::chrono::tai_clock::from_utc(std::chrono::utc_time::max() - offset + 1us), + "the UTC to TAI conversion would overflow"); + + (void)std::chrono::tai_clock::from_utc(std::chrono::utc_time::max() - offset); + TEST_LIBCPP_ASSERT_FAILURE( + std::chrono::tai_clock::from_utc(std::chrono::utc_time::max() - offset + 1ms), + "the UTC to TAI conversion would overflow"); + + (void)std::chrono::tai_clock::from_utc(std::chrono::utc_seconds::max() - offset); + TEST_LIBCPP_ASSERT_FAILURE(std::chrono::tai_clock::from_utc(std::chrono::utc_seconds::max() - offset + 1s), + "the UTC to TAI conversion would overflow"); + + // The conversion uses `common_type_t` so types "larger" + // than seconds are converted to seconds. Types "larger" than seconds are + // stored in "smaller" intergral and the overflow can never occur. + + // Validate the types can never overflow on all current (and future) supported platforms. + static_assert(std::chrono::utc_time::max() <= std::chrono::utc_seconds::max() - offset); + static_assert(std::chrono::utc_time::max() <= std::chrono::utc_seconds::max() - offset); + static_assert(std::chrono::utc_time::max() <= std::chrono::utc_seconds::max() - offset); + static_assert(std::chrono::utc_time::max() <= std::chrono::utc_seconds::max() - offset); + + // Validate the run-time conversion works. + (void)std::chrono::tai_clock::from_utc(std::chrono::utc_time::max()); + (void)std::chrono::tai_clock::from_utc(std::chrono::utc_time::max()); + (void)std::chrono::tai_clock::from_utc(std::chrono::utc_time::max()); + (void)std::chrono::tai_clock::from_utc(std::chrono::utc_time::max()); + + return 0; +} diff --git a/libcxx/test/libcxx/time/time.clock/time.clock.tai/time.clock.tai.members/assert.to_utc.pass.cpp b/libcxx/test/libcxx/time/time.clock/time.clock.tai/time.clock.tai.members/assert.to_utc.pass.cpp new file mode 100644 index 00000000000000..b0e2cbc308c0c4 --- /dev/null +++ b/libcxx/test/libcxx/time/time.clock/time.clock.tai/time.clock.tai.members/assert.to_utc.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-filesystem, no-localization, no-tzdb + +// XFAIL: libcpp-has-no-experimental-tzdb +// XFAIL: availability-tzdb-missing + +// REQUIRES: has-unix-headers +// UNSUPPORTED: libcpp-hardening-mode=none +// XFAIL: libcpp-hardening-mode=fast && availability-verbose_abort-missing + +// +// +// class tai_clock; + +// static utc_time> +// to_utc(const tai_time<_Duration>& t) noexcept; + +#include + +#include "check_assertion.h" + +// The function is specified as +// utc_time>{t.time_since_epoch()} - 378691210s +// When t == t.min() there will be a signed integral underlow (other values too). +int main(int, char**) { + using namespace std::literals::chrono_literals; + constexpr std::chrono::seconds offset{378691210}; + + (void)std::chrono::tai_clock::to_utc(std::chrono::tai_time::min() + offset); + TEST_LIBCPP_ASSERT_FAILURE( + std::chrono::tai_clock::to_utc(std::chrono::tai_time::min() + offset - 1ns), + "the TAI to UTC conversion would underflow"); + + (void)std::chrono::tai_clock::to_utc(std::chrono::tai_time::min() + offset); + TEST_LIBCPP_ASSERT_FAILURE( + std::chrono::tai_clock::to_utc(std::chrono::tai_time::min() + offset - 1us), + "the TAI to UTC conversion would underflow"); + + (void)std::chrono::tai_clock::to_utc(std::chrono::tai_time::min() + offset); + TEST_LIBCPP_ASSERT_FAILURE( + std::chrono::tai_clock::to_utc(std::chrono::tai_time::min() + offset - 1ms), + "the TAI to UTC conversion would underflow"); + + (void)std::chrono::tai_clock::to_utc(std::chrono::tai_seconds::min() + offset); + TEST_LIBCPP_ASSERT_FAILURE(std::chrono::tai_clock::to_utc(std::chrono::tai_seconds::min() + offset - 1s), + "the TAI to UTC conversion would underflow"); + + // The conversion uses `common_type_t` so types "larger" + // than seconds are converted to seconds. Types "larger" than seconds are + // stored in "smaller" intergral and the underflow can never occur. + + // Validate the types can never underflow on all current (and future) supported platforms. + static_assert(std::chrono::tai_time::min() >= std::chrono::tai_seconds::min() + offset); + static_assert(std::chrono::tai_time::min() >= std::chrono::tai_seconds::min() + offset); + static_assert(std::chrono::tai_time::min() >= std::chrono::tai_seconds::min() + offset); + static_assert(std::chrono::tai_time::min() >= std::chrono::tai_seconds::min() + offset); + + // Validate the run-time conversion works. + (void)std::chrono::tai_clock::to_utc(std::chrono::tai_time::min()); + (void)std::chrono::tai_clock::to_utc(std::chrono::tai_time::min()); + (void)std::chrono::tai_clock::to_utc(std::chrono::tai_time::min()); + (void)std::chrono::tai_clock::to_utc(std::chrono::tai_time::min()); + + return 0; +} diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp index 3407fb27c66928..e4f953118fd435 100644 --- a/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp +++ b/libcxx/test/std/time/time.clock/time.clock.tai/tai_time.ostream.pass.cpp @@ -13,7 +13,7 @@ // TODO FMT This test should not require std::to_chars(floating-point) // XFAIL: availability-fp_to_chars-missing -// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: libcpp-has-no-experimental-tzdb // XFAIL: availability-tzdb-missing // REQUIRES: locale.fr_FR.UTF-8 diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp index 807d3f3120b72a..0d2d7bec163011 100644 --- a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/from_utc.pass.cpp @@ -9,7 +9,7 @@ // REQUIRES: std-at-least-c++20 // UNSUPPORTED: no-filesystem, no-localization, no-tzdb -// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: libcpp-has-no-experimental-tzdb // XFAIL: availability-tzdb-missing // diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp index 83736380f293b6..b74e88273f36b1 100644 --- a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/now.pass.cpp @@ -9,7 +9,7 @@ // REQUIRES: std-at-least-c++20 // UNSUPPORTED: no-filesystem, no-localization, no-tzdb -// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: libcpp-has-no-experimental-tzdb // XFAIL: availability-tzdb-missing // diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp index e8d95737161108..38b50bf2758719 100644 --- a/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp +++ b/libcxx/test/std/time/time.clock/time.clock.tai/time.clock.tai.members/to_utc.pass.cpp @@ -9,7 +9,7 @@ // REQUIRES: std-at-least-c++20 // UNSUPPORTED: no-filesystem, no-localization, no-tzdb -// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: libcpp-has-no-experimental-tzdb // XFAIL: availability-tzdb-missing // diff --git a/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp index 0df21e6d858723..ddb057333f49a9 100644 --- a/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp +++ b/libcxx/test/std/time/time.clock/time.clock.tai/types.compile.pass.cpp @@ -9,7 +9,7 @@ // REQUIRES: std-at-least-c++20 // UNSUPPORTED: no-filesystem, no-localization, no-tzdb -// XFAIL: libcpp-has-no-incomplete-tzdb +// XFAIL: libcpp-has-no-experimental-tzdb // XFAIL: availability-tzdb-missing // From libcxx-commits at lists.llvm.org Tue Feb 4 13:03:55 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Tue, 04 Feb 2025 13:03:55 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix ambiguous call in {ranges, std}::count (PR #122529) In-Reply-To: Message-ID: <67a280bb.170a0220.12938f.0053@mx.google.com> https://github.com/winner245 edited https://github.com/llvm/llvm-project/pull/122529 From libcxx-commits at lists.llvm.org Tue Feb 4 13:04:30 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Tue, 04 Feb 2025 13:04:30 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix ambiguous call in {ranges, std}::count (PR #122529) In-Reply-To: Message-ID: <67a280de.170a0220.230eef.190b@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/122529 >From 96780d5e1be5914efffaef5486cdf67da40df9aa Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Fri, 10 Jan 2025 14:57:14 -0500 Subject: [PATCH] Fix ambiguous call in ranges::count & std::count for vector::iterator --- libcxx/include/__algorithm/count.h | 10 +- libcxx/include/__bit/popcount.h | 86 ++++++++++++--- libcxx/include/__bit_reference | 14 +++ libcxx/include/__fwd/bit_reference.h | 8 ++ .../alg.nonmodifying/alg.count/count.pass.cpp | 27 +++++ .../alg.count/ranges.count.pass.cpp | 101 ++++++++++++------ libcxx/test/support/sized_allocator.h | 58 ++++++++++ 7 files changed, 253 insertions(+), 51 deletions(-) create mode 100644 libcxx/test/support/sized_allocator.h diff --git a/libcxx/include/__algorithm/count.h b/libcxx/include/__algorithm/count.h index cd9125779ec64e9..48ce9f8edb621ec 100644 --- a/libcxx/include/__algorithm/count.h +++ b/libcxx/include/__algorithm/count.h @@ -55,18 +55,18 @@ __count_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_t if (__first.__ctz_ != 0) { __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - __r = std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); + __storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_); + __r = std::__popcount(__storage_type(std::__invert_if(*__first.__seg_) & __m)); __n -= __dn; ++__first.__seg_; } // do middle whole words for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) - __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_)); + __r += std::__popcount(__storage_type(std::__invert_if(*__first.__seg_))); // do last partial word if (__n > 0) { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); + __storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); + __r += std::__popcount(__storage_type(std::__invert_if(*__first.__seg_) & __m)); } return __r; } diff --git a/libcxx/include/__bit/popcount.h b/libcxx/include/__bit/popcount.h index 5cf0a01d0733823..2adb3449318ae12 100644 --- a/libcxx/include/__bit/popcount.h +++ b/libcxx/include/__bit/popcount.h @@ -15,6 +15,8 @@ #include <__bit/rotate.h> #include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -38,31 +40,87 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned lo return __builtin_popcountll(__x); } -#if _LIBCPP_STD_VER >= 20 - -template <__libcpp_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noexcept { -# if __has_builtin(__builtin_popcountg) - return __builtin_popcountg(__t); -# else // __has_builtin(__builtin_popcountg) - if (sizeof(_Tp) <= sizeof(unsigned int)) +#if _LIBCPP_STD_VER >= 17 +// Constexpr implementation using constexpr if for C++17 and later +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int __popcount(_Tp __t) _NOEXCEPT { + if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_popcount(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { return std::__libcpp_popcount(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_popcount(static_cast(__t)); - else { + } else { int __ret = 0; while (__t != 0) { __ret += std::__libcpp_popcount(static_cast(__t)); - __t >>= numeric_limits::digits; + __t >>= std::numeric_limits::digits; } return __ret; } -# endif // __has_builtin(__builtin_popcountg) } -#endif // _LIBCPP_STD_VER >= 20 +#else +// Equivalent constexpr implementation using SFINAE for C++11 and C++14 + +template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount(_Tp __t) _NOEXCEPT { + return std::__libcpp_popcount(static_cast(__t)); +} + +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && + sizeof(_Tp) <= sizeof(unsigned long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount(_Tp __t) _NOEXCEPT { + return std::__libcpp_popcount(static_cast(__t)); +} + +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && + sizeof(_Tp) <= sizeof(unsigned long long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount(_Tp __t) _NOEXCEPT { + return std::__libcpp_popcount(static_cast(__t)); +} + +# if _LIBCPP_STD_VER == 11 +// A recursive constexpr implementation for C++11 +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount(_Tp __t) _NOEXCEPT { + return __t != 0 ? std::__libcpp_popcount(static_cast(__t)) + + std::__popcount<_Tp>(__t >> numeric_limits::digits) + : 0; +} + +# else +// Constexpr implementation for C++14 (non-constexpr for C++03, 98) +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __popcount(_Tp __t) _NOEXCEPT { + int __ret = 0; + while (__t != 0) { + __ret += std::__libcpp_popcount(static_cast(__t)); + __t >>= numeric_limits::digits; + } + return __ret; +} + +# endif // _LIBCPP_STD_VER == 11 + +#endif // _LIBCPP_STD_VER >= 17 + +#if _LIBCPP_STD_VER >= 20 + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noexcept { +# if __has_builtin(__builtin_popcountg) + return __builtin_popcountg(__t); +# else + return std::__popcount(__t); +# endif +} + +#endif _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c398059..ffde3e77df98fa2 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -58,6 +58,20 @@ struct __size_difference_type_traits<_Cp, __void_t +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz) { + static_assert(is_unsigned<_StorageType>::value, "__trailing_mask only works with unsigned types"); + return static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) { + static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types"); + return static_cast<_StorageType>( + static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz) & + std::__trailing_mask<_StorageType>(__clz)); +} + template ::value> class __bit_reference { using __storage_type _LIBCPP_NODEBUG = typename _Cp::__storage_type; diff --git a/libcxx/include/__fwd/bit_reference.h b/libcxx/include/__fwd/bit_reference.h index 30462b6ce4c92f8..b9188336deba5cc 100644 --- a/libcxx/include/__fwd/bit_reference.h +++ b/libcxx/include/__fwd/bit_reference.h @@ -10,6 +10,8 @@ #define _LIBCPP___FWD_BIT_REFERENCE_H #include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -23,6 +25,12 @@ class __bit_iterator; template struct __size_difference_type_traits; +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz); + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz); + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___FWD_BIT_REFERENCE_H diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp index 7250c49a7ff9528..f40e4444fec2ce0 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp @@ -15,12 +15,14 @@ // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000 +// XFAIL: FROZEN-CXX03-HEADERS-FIXME #include #include #include #include +#include "sized_allocator.h" #include "test_macros.h" #include "test_iterators.h" #include "type_algorithms.h" @@ -36,6 +38,29 @@ struct Test { } }; +TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 100); + } + { + using Alloc = sized_allocator; + std::vector in(199, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 199); + } + { + using Alloc = sized_allocator; + std::vector in(200, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 200); + } + { + using Alloc = sized_allocator; + std::vector in(257, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 257); + } +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::cpp17_input_iterator_list(), Test()); @@ -51,6 +76,8 @@ TEST_CONSTEXPR_CXX20 bool test() { } } + test_bit_iterator_with_custom_sized_types(); + return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp index 6030bed47ec6a76..b24d3046fb4bb46 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp @@ -29,6 +29,7 @@ #include #include +#include "sized_allocator.h" #include "almost_satisfies_types.h" #include "test_iterators.h" @@ -67,13 +68,13 @@ constexpr void test_iterators() { { // simple test { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; std::same_as auto ret = std::ranges::count(It(a), Sent(It(a + 4)), 3); assert(ret == 1); } { - int a[] = {1, 2, 3, 4}; - auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); + int a[] = {1, 2, 3, 4}; + auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); std::same_as auto ret = std::ranges::count(range, 3); assert(ret == 1); } @@ -83,13 +84,13 @@ constexpr void test_iterators() { // check that an empty range works { std::array a = {}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1); assert(ret == 0); } { std::array a = {}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 1); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 1); assert(ret == 0); } } @@ -98,13 +99,13 @@ constexpr void test_iterators() { // check that a range with a single element works { std::array a = {2}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2); assert(ret == 1); } { std::array a = {2}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 2); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 2); assert(ret == 1); } } @@ -113,13 +114,13 @@ constexpr void test_iterators() { // check that 0 is returned with no match { std::array a = {1, 1, 1}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0); assert(ret == 0); } { std::array a = {1, 1, 1}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 0); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 0); assert(ret == 0); } } @@ -128,13 +129,13 @@ constexpr void test_iterators() { // check that more than one element is counted { std::array a = {3, 3, 4, 3, 3}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3); assert(ret == 4); } { std::array a = {3, 3, 4, 3, 3}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 3); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 3); assert(ret == 4); } } @@ -143,18 +144,41 @@ constexpr void test_iterators() { // check that all elements are counted { std::array a = {5, 5, 5, 5}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5); assert(ret == 4); } { std::array a = {5, 5, 5, 5}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 5); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 5); assert(ret == 4); } } } +TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, true, Alloc(1)); + assert(std::ranges::count(in, true) == 100); + } + { + using Alloc = sized_allocator; + std::vector in(199, true, Alloc(1)); + assert(std::ranges::count(in, true) == 199); + } + { + using Alloc = sized_allocator; + std::vector in(200, true, Alloc(1)); + assert(std::ranges::count(in, true) == 200); + } + { + using Alloc = sized_allocator; + std::vector in(257, true, Alloc(1)); + assert(std::ranges::count(in, true) == 257); + } +} + constexpr bool test() { test_iterators(); test_iterators(); @@ -167,12 +191,12 @@ constexpr bool test() { { // check that projections are used properly and that they are called with the iterator directly { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; auto ret = std::ranges::count(a, a + 4, a + 3, [](int& i) { return &i; }); assert(ret == 1); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; auto ret = std::ranges::count(a, a + 3, [](int& i) { return &i; }); assert(ret == 1); } @@ -180,8 +204,10 @@ constexpr bool test() { { // check that std::invoke is used - struct S { int i; }; - S a[] = { S{1}, S{3}, S{2} }; + struct S { + int i; + }; + S a[] = {S{1}, S{3}, S{2}}; std::same_as auto ret = std::ranges::count(a, 4, &S::i); assert(ret == 0); } @@ -189,16 +215,22 @@ constexpr bool test() { { // count invocations of the projection { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::count(a, a + 4, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::count(a, a + 4, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == 1); assert(projection_count == 4); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::count(a, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::count(a, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == 1); assert(projection_count == 4); } @@ -208,7 +240,7 @@ constexpr bool test() { // check that an immobile type works struct NonMovable { NonMovable(const NonMovable&) = delete; - NonMovable(NonMovable&&) = delete; + NonMovable(NonMovable&&) = delete; constexpr NonMovable(int i_) : i(i_) {} int i; @@ -216,12 +248,12 @@ constexpr bool test() { }; { NonMovable a[] = {9, 8, 4, 3}; - auto ret = std::ranges::count(a, a + 4, NonMovable(8)); + auto ret = std::ranges::count(a, a + 4, NonMovable(8)); assert(ret == 1); } { NonMovable a[] = {9, 8, 4, 3}; - auto ret = std::ranges::count(a, NonMovable(8)); + auto ret = std::ranges::count(a, NonMovable(8)); assert(ret == 1); } } @@ -230,7 +262,7 @@ constexpr bool test() { // check that difference_type is used struct DiffTypeIterator { using difference_type = signed char; - using value_type = int; + using value_type = int; int* it = nullptr; @@ -238,7 +270,10 @@ constexpr bool test() { constexpr DiffTypeIterator(int* i) : it(i) {} constexpr int& operator*() const { return *it; } - constexpr DiffTypeIterator& operator++() { ++it; return *this; } + constexpr DiffTypeIterator& operator++() { + ++it; + return *this; + } constexpr void operator++(int) { ++it; } bool operator==(const DiffTypeIterator&) const = default; @@ -251,7 +286,7 @@ constexpr bool test() { assert(ret == 1); } { - int a[] = {5, 5, 4, 3, 2, 1}; + int a[] = {5, 5, 4, 3, 2, 1}; auto range = std::ranges::subrange(DiffTypeIterator(a), DiffTypeIterator(a + 6)); std::same_as decltype(auto) ret = std::ranges::count(range, 4); assert(ret == 1); @@ -270,6 +305,8 @@ constexpr bool test() { } } + test_bit_iterator_with_custom_sized_types(); + return true; } diff --git a/libcxx/test/support/sized_allocator.h b/libcxx/test/support/sized_allocator.h new file mode 100644 index 000000000000000..a877252e82962c7 --- /dev/null +++ b/libcxx/test/support/sized_allocator.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_SUPPORT_SIZED_ALLOCATOR_H +#define TEST_SUPPORT_SIZED_ALLOCATOR_H + +#include +#include +#include +#include + +#include "test_macros.h" + +template +class sized_allocator { + template + friend class sized_allocator; + +public: + using value_type = T; + using size_type = SIZE_TYPE; + using difference_type = DIFF_TYPE; + using propagate_on_container_swap = std::true_type; + + TEST_CONSTEXPR_CXX20 explicit sized_allocator(int d = 0) : data_(d) {} + + template + TEST_CONSTEXPR_CXX20 sized_allocator(const sized_allocator& a) TEST_NOEXCEPT : data_(a.data_) {} + + TEST_CONSTEXPR_CXX20 T* allocate(size_type n) { + if (n > max_size()) + TEST_THROW(std::bad_array_new_length()); + return std::allocator().allocate(n); + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* p, size_type n) TEST_NOEXCEPT { std::allocator().deallocate(p, n); } + + TEST_CONSTEXPR size_type max_size() const TEST_NOEXCEPT { + return std::numeric_limits::max() / sizeof(value_type); + } + +private: + int data_; + + TEST_CONSTEXPR friend bool operator==(const sized_allocator& a, const sized_allocator& b) { + return a.data_ == b.data_; + } + TEST_CONSTEXPR friend bool operator!=(const sized_allocator& a, const sized_allocator& b) { + return a.data_ != b.data_; + } +}; + +#endif From libcxx-commits at lists.llvm.org Tue Feb 4 13:06:18 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Tue, 04 Feb 2025 13:06:18 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197) In-Reply-To: Message-ID: <67a2814a.630a0220.a2ffa.0b94@mx.google.com> ================ @@ -447,10 +449,46 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) { } # endif +// Try constant folding the format string instead of going through the whole formatting machinery. If there is no +// constant folding no extra code should be emitted (with optimizations enabled) and the function returns nullopt. When +// constant folding is successful, the formatting is performed and the resulting string is returned. +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional> __try_constant_folding_format( ---------------- philnik777 wrote: Did you make sure to run the benchmarks with optimizations enabled? I'm quite surprised that there'd be a significant difference, since I couldn't see any unnecessary copying in the assembly. I'd also like to optimize formatting integers and similar stuff later, which requires a string. https://github.com/llvm/llvm-project/pull/107197 From libcxx-commits at lists.llvm.org Tue Feb 4 13:11:30 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Tue, 04 Feb 2025 13:11:30 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Replace __is_trivially_relocatable by is_trivially_copyable (PR #124970) In-Reply-To: Message-ID: <67a28282.050a0220.10bbc2.12b6@mx.google.com> https://github.com/philnik777 approved this pull request. https://github.com/llvm/llvm-project/pull/124970 From libcxx-commits at lists.llvm.org Tue Feb 4 13:52:21 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 13:52:21 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Reduce the dependency of the locale base API on the base system from the headers (PR #117764) In-Reply-To: Message-ID: <67a28c15.a70a0220.e3a1a.2004@mx.google.com> https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/117764 >From a48659399e399a4cf9112e1a4c37dea5d2484bd6 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 26 Nov 2024 12:27:08 -0500 Subject: [PATCH] [libc++] Reduce the dependency of the locale base API on the base system from the headers Many parts of the locale base API are only required when building the shared/static library, but not from the headers. Document those functions and carve out a few of those that don't work when _XOPEN_SOURCE is defined to something old. Fixes #117630 --- libcxx/include/__locale_dir/locale_base_api.h | 17 +++++--- .../include/__locale_dir/support/bsd_like.h | 4 ++ libcxx/test/libcxx/xopen_source.gen.py | 42 +++++++++++++++++++ 3 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 libcxx/test/libcxx/xopen_source.gen.py diff --git a/libcxx/include/__locale_dir/locale_base_api.h b/libcxx/include/__locale_dir/locale_base_api.h index bbee9f49867fd9..e9d868148bb47f 100644 --- a/libcxx/include/__locale_dir/locale_base_api.h +++ b/libcxx/include/__locale_dir/locale_base_api.h @@ -23,12 +23,16 @@ // Variadic functions may be implemented as templates with a parameter pack instead // of C-style variadic functions. // +// Most of these functions are only required when building the library. Functions that are also +// required when merely using the headers are marked as such below. +// // TODO: __localeconv shouldn't take a reference, but the Windows implementation doesn't allow copying __locale_t +// TODO: Eliminate the need for any of these functions from the headers. // // Locale management // ----------------- // namespace __locale { -// using __locale_t = implementation-defined; +// using __locale_t = implementation-defined; // required by the headers // using __lconv_t = implementation-defined; // __locale_t __newlocale(int, const char*, __locale_t); // void __freelocale(__locale_t); @@ -60,8 +64,8 @@ // namespace __locale { // int __islower(int, __locale_t); // int __isupper(int, __locale_t); -// int __isdigit(int, __locale_t); -// int __isxdigit(int, __locale_t); +// int __isdigit(int, __locale_t); // required by the headers +// int __isxdigit(int, __locale_t); // required by the headers // int __toupper(int, __locale_t); // int __tolower(int, __locale_t); // int __strcoll(const char*, const char*, __locale_t); @@ -99,9 +103,10 @@ // int __mbtowc(wchar_t*, const char*, size_t, __locale_t); // size_t __mbrlen(const char*, size_t, mbstate_t*, __locale_t); // size_t __mbsrtowcs(wchar_t*, const char**, size_t, mbstate_t*, __locale_t); -// int __snprintf(char*, size_t, __locale_t, const char*, ...); -// int __asprintf(char**, __locale_t, const char*, ...); -// int __sscanf(const char*, __locale_t, const char*, ...); +// +// int __snprintf(char*, size_t, __locale_t, const char*, ...); // required by the headers +// int __asprintf(char**, __locale_t, const char*, ...); // required by the headers +// int __sscanf(const char*, __locale_t, const char*, ...); // required by the headers // } #if defined(__APPLE__) diff --git a/libcxx/include/__locale_dir/support/bsd_like.h b/libcxx/include/__locale_dir/support/bsd_like.h index c0080b13a08cf3..61d5bb45d05f11 100644 --- a/libcxx/include/__locale_dir/support/bsd_like.h +++ b/libcxx/include/__locale_dir/support/bsd_like.h @@ -160,19 +160,23 @@ inline _LIBCPP_HIDE_FROM_ABI wint_t __btowc(int __c, __locale_t __loc) { return inline _LIBCPP_HIDE_FROM_ABI int __wctob(wint_t __c, __locale_t __loc) { return ::wctob_l(__c, __loc); } +# ifdef _LIBCPP_BUILDING_LIBRARY inline _LIBCPP_HIDE_FROM_ABI size_t __wcsnrtombs(char* __dest, const wchar_t** __src, size_t __nwc, size_t __len, mbstate_t* __ps, __locale_t __loc) { return ::wcsnrtombs_l(__dest, __src, __nwc, __len, __ps, __loc); } +# endif inline _LIBCPP_HIDE_FROM_ABI size_t __wcrtomb(char* __s, wchar_t __wc, mbstate_t* __ps, __locale_t __loc) { return ::wcrtomb_l(__s, __wc, __ps, __loc); } +# ifdef _LIBCPP_BUILDING_LIBRARY inline _LIBCPP_HIDE_FROM_ABI size_t __mbsnrtowcs(wchar_t* __dest, const char** __src, size_t __nms, size_t __len, mbstate_t* __ps, __locale_t __loc) { return ::mbsnrtowcs_l(__dest, __src, __nms, __len, __ps, __loc); } +# endif inline _LIBCPP_HIDE_FROM_ABI size_t __mbrtowc(wchar_t* __pwc, const char* __s, size_t __n, mbstate_t* __ps, __locale_t __loc) { diff --git a/libcxx/test/libcxx/xopen_source.gen.py b/libcxx/test/libcxx/xopen_source.gen.py new file mode 100644 index 00000000000000..39b8bd0e8ecef4 --- /dev/null +++ b/libcxx/test/libcxx/xopen_source.gen.py @@ -0,0 +1,42 @@ +# ===----------------------------------------------------------------------===## +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ===----------------------------------------------------------------------===## + +# Make sure that libc++ headers work when defining _XOPEN_SOURCE=500. +# We may not want to guarantee this forever, but since this works today and +# it's something that users rely on, it makes sense to put a test on it. +# +# https://github.com/llvm/llvm-project/issues/117630 + +# RUN: %{python} %s %{libcxx-dir}/utils + +import sys + +sys.path.append(sys.argv[1]) +from libcxx.header_information import ( + lit_header_restrictions, + lit_header_undeprecations, + public_headers, +) + +for header in public_headers: + for version in (500, 600, 700): + # TODO: currently uses ::fseeko unguarded, which fails with _XOPEN_SOURCE=500. + if header == "fstream" and version == 500: + continue + + print( + f"""\ +//--- {header}.xopen_source_{version}.compile.pass.cpp +{lit_header_restrictions.get(header, '')} +{lit_header_undeprecations.get(header, '')} + +// ADDITIONAL_COMPILE_FLAGS: -D_XOPEN_SOURCE={version} + +#include <{header}> +""" + ) From libcxx-commits at lists.llvm.org Tue Feb 4 13:53:42 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Tue, 04 Feb 2025 13:53:42 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix ambiguous call in {ranges, std}::count (PR #122529) In-Reply-To: Message-ID: <67a28c66.170a0220.2516e9.c6cf@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/122529 >From e8b48d4c1ed0fb76ba2e0c99dca5e685a10a8599 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Fri, 10 Jan 2025 14:57:14 -0500 Subject: [PATCH] Fix ambiguous call in ranges::count & std::count for vector::iterator --- libcxx/include/__algorithm/count.h | 10 +- libcxx/include/__bit/popcount.h | 84 ++++++++++++--- libcxx/include/__bit_reference | 15 +++ libcxx/include/__fwd/bit_reference.h | 6 ++ .../alg.nonmodifying/alg.count/count.pass.cpp | 27 +++++ .../alg.count/ranges.count.pass.cpp | 101 ++++++++++++------ libcxx/test/support/sized_allocator.h | 58 ++++++++++ 7 files changed, 248 insertions(+), 53 deletions(-) create mode 100644 libcxx/test/support/sized_allocator.h diff --git a/libcxx/include/__algorithm/count.h b/libcxx/include/__algorithm/count.h index cd9125779ec64e9..48ce9f8edb621ec 100644 --- a/libcxx/include/__algorithm/count.h +++ b/libcxx/include/__algorithm/count.h @@ -55,18 +55,18 @@ __count_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_t if (__first.__ctz_ != 0) { __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - __r = std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); + __storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_); + __r = std::__popcount(__storage_type(std::__invert_if(*__first.__seg_) & __m)); __n -= __dn; ++__first.__seg_; } // do middle whole words for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) - __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_)); + __r += std::__popcount(__storage_type(std::__invert_if(*__first.__seg_))); // do last partial word if (__n > 0) { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); + __storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); + __r += std::__popcount(__storage_type(std::__invert_if(*__first.__seg_) & __m)); } return __r; } diff --git a/libcxx/include/__bit/popcount.h b/libcxx/include/__bit/popcount.h index 5cf0a01d0733823..6999bf55d704454 100644 --- a/libcxx/include/__bit/popcount.h +++ b/libcxx/include/__bit/popcount.h @@ -15,6 +15,8 @@ #include <__bit/rotate.h> #include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -38,34 +40,84 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned lo return __builtin_popcountll(__x); } -#if _LIBCPP_STD_VER >= 20 - -template <__libcpp_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noexcept { -# if __has_builtin(__builtin_popcountg) - return __builtin_popcountg(__t); -# else // __has_builtin(__builtin_popcountg) - if (sizeof(_Tp) <= sizeof(unsigned int)) +#ifndef _LIBCPP_CXX03_LANG +// Constexpr __popcount implementation for C++11 and later +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr int __popcount(_Tp __t) _NOEXCEPT { + if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_popcount(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { return std::__libcpp_popcount(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_popcount(static_cast(__t)); - else { + } else { +# if _LIBCPP_STD_VER == 11 + // A recursive constexpr implementation for C++11 + return __t != 0 ? std::__libcpp_popcount(static_cast(__t)) + + std::__popcount<_Tp>(__t >> numeric_limits::digits) + : 0; +# else int __ret = 0; while (__t != 0) { __ret += std::__libcpp_popcount(static_cast(__t)); - __t >>= numeric_limits::digits; + __t >>= std::numeric_limits::digits; } return __ret; } -# endif // __has_builtin(__builtin_popcountg) +# endif // _LIBCPP_STD_VER == 11 + } + +#else +// Equivalent __popcount implementation using SFINAE-based overloading for C++03 + +template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> +_LIBCPP_HIDE_FROM_ABI int __popcount(_Tp __t) { + return std::__libcpp_popcount(static_cast(__t)); +} + +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && + sizeof(_Tp) <= sizeof(unsigned long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI int __popcount(_Tp __t) { + return std::__libcpp_popcount(static_cast(__t)); +} + +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && + sizeof(_Tp) <= sizeof(unsigned long long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI int __popcount(_Tp __t) { + return std::__libcpp_popcount(static_cast(__t)); +} + +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI int __popcount(_Tp __t) { + int __ret = 0; + while (__t != 0) { + __ret += std::__libcpp_popcount(static_cast(__t)); + __t >>= numeric_limits::digits; + } + return __ret; } -#endif // _LIBCPP_STD_VER >= 20 +#endif // _LIBCPP_CXX03_LANG + +#if _LIBCPP_STD_VER >= 20 + + template <__libcpp_unsigned_integer _Tp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noexcept { +# if __has_builtin(__builtin_popcountg) + return __builtin_popcountg(__t); +# else + return std::__popcount(__t); +# endif + } + +#endif -_LIBCPP_END_NAMESPACE_STD + _LIBCPP_END_NAMESPACE_STD -_LIBCPP_POP_MACROS + _LIBCPP_POP_MACROS #endif // _LIBCPP___BIT_POPCOUNT_H diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c398059..5d946ac163354e3 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -25,6 +25,7 @@ #include <__memory/pointer_traits.h> #include <__type_traits/conditional.h> #include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_unsigned.h> #include <__type_traits/void_t.h> #include <__utility/pair.h> #include <__utility/swap.h> @@ -58,6 +59,20 @@ struct __size_difference_type_traits<_Cp, __void_t +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz) { + static_assert(is_unsigned<_StorageType>::value, "__trailing_mask only works with unsigned types"); + return static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) { + static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types"); + return static_cast<_StorageType>( + static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz) & + std::__trailing_mask<_StorageType>(__clz)); +} + template ::value> class __bit_reference { using __storage_type _LIBCPP_NODEBUG = typename _Cp::__storage_type; diff --git a/libcxx/include/__fwd/bit_reference.h b/libcxx/include/__fwd/bit_reference.h index 30462b6ce4c92f8..220366351ba7523 100644 --- a/libcxx/include/__fwd/bit_reference.h +++ b/libcxx/include/__fwd/bit_reference.h @@ -23,6 +23,12 @@ class __bit_iterator; template struct __size_difference_type_traits; +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz); + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz); + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___FWD_BIT_REFERENCE_H diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp index 7250c49a7ff9528..f40e4444fec2ce0 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp @@ -15,12 +15,14 @@ // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000 +// XFAIL: FROZEN-CXX03-HEADERS-FIXME #include #include #include #include +#include "sized_allocator.h" #include "test_macros.h" #include "test_iterators.h" #include "type_algorithms.h" @@ -36,6 +38,29 @@ struct Test { } }; +TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 100); + } + { + using Alloc = sized_allocator; + std::vector in(199, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 199); + } + { + using Alloc = sized_allocator; + std::vector in(200, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 200); + } + { + using Alloc = sized_allocator; + std::vector in(257, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 257); + } +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::cpp17_input_iterator_list(), Test()); @@ -51,6 +76,8 @@ TEST_CONSTEXPR_CXX20 bool test() { } } + test_bit_iterator_with_custom_sized_types(); + return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp index 6030bed47ec6a76..b24d3046fb4bb46 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp @@ -29,6 +29,7 @@ #include #include +#include "sized_allocator.h" #include "almost_satisfies_types.h" #include "test_iterators.h" @@ -67,13 +68,13 @@ constexpr void test_iterators() { { // simple test { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; std::same_as auto ret = std::ranges::count(It(a), Sent(It(a + 4)), 3); assert(ret == 1); } { - int a[] = {1, 2, 3, 4}; - auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); + int a[] = {1, 2, 3, 4}; + auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); std::same_as auto ret = std::ranges::count(range, 3); assert(ret == 1); } @@ -83,13 +84,13 @@ constexpr void test_iterators() { // check that an empty range works { std::array a = {}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1); assert(ret == 0); } { std::array a = {}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 1); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 1); assert(ret == 0); } } @@ -98,13 +99,13 @@ constexpr void test_iterators() { // check that a range with a single element works { std::array a = {2}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2); assert(ret == 1); } { std::array a = {2}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 2); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 2); assert(ret == 1); } } @@ -113,13 +114,13 @@ constexpr void test_iterators() { // check that 0 is returned with no match { std::array a = {1, 1, 1}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0); assert(ret == 0); } { std::array a = {1, 1, 1}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 0); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 0); assert(ret == 0); } } @@ -128,13 +129,13 @@ constexpr void test_iterators() { // check that more than one element is counted { std::array a = {3, 3, 4, 3, 3}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3); assert(ret == 4); } { std::array a = {3, 3, 4, 3, 3}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 3); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 3); assert(ret == 4); } } @@ -143,18 +144,41 @@ constexpr void test_iterators() { // check that all elements are counted { std::array a = {5, 5, 5, 5}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5); assert(ret == 4); } { std::array a = {5, 5, 5, 5}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 5); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 5); assert(ret == 4); } } } +TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, true, Alloc(1)); + assert(std::ranges::count(in, true) == 100); + } + { + using Alloc = sized_allocator; + std::vector in(199, true, Alloc(1)); + assert(std::ranges::count(in, true) == 199); + } + { + using Alloc = sized_allocator; + std::vector in(200, true, Alloc(1)); + assert(std::ranges::count(in, true) == 200); + } + { + using Alloc = sized_allocator; + std::vector in(257, true, Alloc(1)); + assert(std::ranges::count(in, true) == 257); + } +} + constexpr bool test() { test_iterators(); test_iterators(); @@ -167,12 +191,12 @@ constexpr bool test() { { // check that projections are used properly and that they are called with the iterator directly { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; auto ret = std::ranges::count(a, a + 4, a + 3, [](int& i) { return &i; }); assert(ret == 1); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; auto ret = std::ranges::count(a, a + 3, [](int& i) { return &i; }); assert(ret == 1); } @@ -180,8 +204,10 @@ constexpr bool test() { { // check that std::invoke is used - struct S { int i; }; - S a[] = { S{1}, S{3}, S{2} }; + struct S { + int i; + }; + S a[] = {S{1}, S{3}, S{2}}; std::same_as auto ret = std::ranges::count(a, 4, &S::i); assert(ret == 0); } @@ -189,16 +215,22 @@ constexpr bool test() { { // count invocations of the projection { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::count(a, a + 4, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::count(a, a + 4, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == 1); assert(projection_count == 4); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::count(a, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::count(a, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == 1); assert(projection_count == 4); } @@ -208,7 +240,7 @@ constexpr bool test() { // check that an immobile type works struct NonMovable { NonMovable(const NonMovable&) = delete; - NonMovable(NonMovable&&) = delete; + NonMovable(NonMovable&&) = delete; constexpr NonMovable(int i_) : i(i_) {} int i; @@ -216,12 +248,12 @@ constexpr bool test() { }; { NonMovable a[] = {9, 8, 4, 3}; - auto ret = std::ranges::count(a, a + 4, NonMovable(8)); + auto ret = std::ranges::count(a, a + 4, NonMovable(8)); assert(ret == 1); } { NonMovable a[] = {9, 8, 4, 3}; - auto ret = std::ranges::count(a, NonMovable(8)); + auto ret = std::ranges::count(a, NonMovable(8)); assert(ret == 1); } } @@ -230,7 +262,7 @@ constexpr bool test() { // check that difference_type is used struct DiffTypeIterator { using difference_type = signed char; - using value_type = int; + using value_type = int; int* it = nullptr; @@ -238,7 +270,10 @@ constexpr bool test() { constexpr DiffTypeIterator(int* i) : it(i) {} constexpr int& operator*() const { return *it; } - constexpr DiffTypeIterator& operator++() { ++it; return *this; } + constexpr DiffTypeIterator& operator++() { + ++it; + return *this; + } constexpr void operator++(int) { ++it; } bool operator==(const DiffTypeIterator&) const = default; @@ -251,7 +286,7 @@ constexpr bool test() { assert(ret == 1); } { - int a[] = {5, 5, 4, 3, 2, 1}; + int a[] = {5, 5, 4, 3, 2, 1}; auto range = std::ranges::subrange(DiffTypeIterator(a), DiffTypeIterator(a + 6)); std::same_as decltype(auto) ret = std::ranges::count(range, 4); assert(ret == 1); @@ -270,6 +305,8 @@ constexpr bool test() { } } + test_bit_iterator_with_custom_sized_types(); + return true; } diff --git a/libcxx/test/support/sized_allocator.h b/libcxx/test/support/sized_allocator.h new file mode 100644 index 000000000000000..a877252e82962c7 --- /dev/null +++ b/libcxx/test/support/sized_allocator.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_SUPPORT_SIZED_ALLOCATOR_H +#define TEST_SUPPORT_SIZED_ALLOCATOR_H + +#include +#include +#include +#include + +#include "test_macros.h" + +template +class sized_allocator { + template + friend class sized_allocator; + +public: + using value_type = T; + using size_type = SIZE_TYPE; + using difference_type = DIFF_TYPE; + using propagate_on_container_swap = std::true_type; + + TEST_CONSTEXPR_CXX20 explicit sized_allocator(int d = 0) : data_(d) {} + + template + TEST_CONSTEXPR_CXX20 sized_allocator(const sized_allocator& a) TEST_NOEXCEPT : data_(a.data_) {} + + TEST_CONSTEXPR_CXX20 T* allocate(size_type n) { + if (n > max_size()) + TEST_THROW(std::bad_array_new_length()); + return std::allocator().allocate(n); + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* p, size_type n) TEST_NOEXCEPT { std::allocator().deallocate(p, n); } + + TEST_CONSTEXPR size_type max_size() const TEST_NOEXCEPT { + return std::numeric_limits::max() / sizeof(value_type); + } + +private: + int data_; + + TEST_CONSTEXPR friend bool operator==(const sized_allocator& a, const sized_allocator& b) { + return a.data_ == b.data_; + } + TEST_CONSTEXPR friend bool operator!=(const sized_allocator& a, const sized_allocator& b) { + return a.data_ != b.data_; + } +}; + +#endif From libcxx-commits at lists.llvm.org Tue Feb 4 13:54:37 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 13:54:37 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Reduce the dependency of the locale base API on the base system from the headers (PR #117764) In-Reply-To: Message-ID: <67a28c9d.170a0220.255e2b.e966@mx.google.com> ldionne wrote: It turns out this is breaking more code than I thought. I'll try to push this through the finish line and cherry-pick into LLVM 20. https://github.com/llvm/llvm-project/pull/117764 From libcxx-commits at lists.llvm.org Tue Feb 4 13:54:42 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Tue, 04 Feb 2025 13:54:42 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Reduce the dependency of the locale base API on the base system from the headers (PR #117764) In-Reply-To: Message-ID: <67a28ca2.a70a0220.e3a1a.2062@mx.google.com> https://github.com/ldionne milestoned https://github.com/llvm/llvm-project/pull/117764 From libcxx-commits at lists.llvm.org Tue Feb 4 14:17:13 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Tue, 04 Feb 2025 14:17:13 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix ambiguous call in {ranges, std}::count (PR #122529) In-Reply-To: Message-ID: <67a291e9.630a0220.143c4.5984@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/122529 >From c6b084e4ca7db3abd1aa71a30a83d2de6a2baace Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Fri, 10 Jan 2025 14:57:14 -0500 Subject: [PATCH] Fix ambiguous call in ranges::count & std::count for vector::iterator --- libcxx/include/__algorithm/count.h | 10 +- libcxx/include/__bit/popcount.h | 84 ++++++++++++--- libcxx/include/__bit_reference | 15 +++ libcxx/include/__fwd/bit_reference.h | 6 ++ .../alg.nonmodifying/alg.count/count.pass.cpp | 27 +++++ .../alg.count/ranges.count.pass.cpp | 101 ++++++++++++------ libcxx/test/support/sized_allocator.h | 58 ++++++++++ 7 files changed, 248 insertions(+), 53 deletions(-) create mode 100644 libcxx/test/support/sized_allocator.h diff --git a/libcxx/include/__algorithm/count.h b/libcxx/include/__algorithm/count.h index cd9125779ec64e9..48ce9f8edb621ec 100644 --- a/libcxx/include/__algorithm/count.h +++ b/libcxx/include/__algorithm/count.h @@ -55,18 +55,18 @@ __count_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_t if (__first.__ctz_ != 0) { __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - __r = std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); + __storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_); + __r = std::__popcount(__storage_type(std::__invert_if(*__first.__seg_) & __m)); __n -= __dn; ++__first.__seg_; } // do middle whole words for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) - __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_)); + __r += std::__popcount(__storage_type(std::__invert_if(*__first.__seg_))); // do last partial word if (__n > 0) { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); + __storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); + __r += std::__popcount(__storage_type(std::__invert_if(*__first.__seg_) & __m)); } return __r; } diff --git a/libcxx/include/__bit/popcount.h b/libcxx/include/__bit/popcount.h index 5cf0a01d0733823..6999bf55d704454 100644 --- a/libcxx/include/__bit/popcount.h +++ b/libcxx/include/__bit/popcount.h @@ -15,6 +15,8 @@ #include <__bit/rotate.h> #include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -38,34 +40,84 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned lo return __builtin_popcountll(__x); } -#if _LIBCPP_STD_VER >= 20 - -template <__libcpp_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noexcept { -# if __has_builtin(__builtin_popcountg) - return __builtin_popcountg(__t); -# else // __has_builtin(__builtin_popcountg) - if (sizeof(_Tp) <= sizeof(unsigned int)) +#ifndef _LIBCPP_CXX03_LANG +// Constexpr __popcount implementation for C++11 and later +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr int __popcount(_Tp __t) _NOEXCEPT { + if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_popcount(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { return std::__libcpp_popcount(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_popcount(static_cast(__t)); - else { + } else { +# if _LIBCPP_STD_VER == 11 + // A recursive constexpr implementation for C++11 + return __t != 0 ? std::__libcpp_popcount(static_cast(__t)) + + std::__popcount<_Tp>(__t >> numeric_limits::digits) + : 0; +# else int __ret = 0; while (__t != 0) { __ret += std::__libcpp_popcount(static_cast(__t)); - __t >>= numeric_limits::digits; + __t >>= std::numeric_limits::digits; } return __ret; } -# endif // __has_builtin(__builtin_popcountg) +# endif // _LIBCPP_STD_VER == 11 + } + +#else +// Equivalent __popcount implementation using SFINAE-based overloading for C++03 + +template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> +_LIBCPP_HIDE_FROM_ABI int __popcount(_Tp __t) { + return std::__libcpp_popcount(static_cast(__t)); +} + +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && + sizeof(_Tp) <= sizeof(unsigned long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI int __popcount(_Tp __t) { + return std::__libcpp_popcount(static_cast(__t)); +} + +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && + sizeof(_Tp) <= sizeof(unsigned long long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI int __popcount(_Tp __t) { + return std::__libcpp_popcount(static_cast(__t)); +} + +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI int __popcount(_Tp __t) { + int __ret = 0; + while (__t != 0) { + __ret += std::__libcpp_popcount(static_cast(__t)); + __t >>= numeric_limits::digits; + } + return __ret; } -#endif // _LIBCPP_STD_VER >= 20 +#endif // _LIBCPP_CXX03_LANG + +#if _LIBCPP_STD_VER >= 20 + + template <__libcpp_unsigned_integer _Tp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noexcept { +# if __has_builtin(__builtin_popcountg) + return __builtin_popcountg(__t); +# else + return std::__popcount(__t); +# endif + } + +#endif -_LIBCPP_END_NAMESPACE_STD + _LIBCPP_END_NAMESPACE_STD -_LIBCPP_POP_MACROS + _LIBCPP_POP_MACROS #endif // _LIBCPP___BIT_POPCOUNT_H diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c398059..5d946ac163354e3 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -25,6 +25,7 @@ #include <__memory/pointer_traits.h> #include <__type_traits/conditional.h> #include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_unsigned.h> #include <__type_traits/void_t.h> #include <__utility/pair.h> #include <__utility/swap.h> @@ -58,6 +59,20 @@ struct __size_difference_type_traits<_Cp, __void_t +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz) { + static_assert(is_unsigned<_StorageType>::value, "__trailing_mask only works with unsigned types"); + return static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) { + static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types"); + return static_cast<_StorageType>( + static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz) & + std::__trailing_mask<_StorageType>(__clz)); +} + template ::value> class __bit_reference { using __storage_type _LIBCPP_NODEBUG = typename _Cp::__storage_type; diff --git a/libcxx/include/__fwd/bit_reference.h b/libcxx/include/__fwd/bit_reference.h index 30462b6ce4c92f8..220366351ba7523 100644 --- a/libcxx/include/__fwd/bit_reference.h +++ b/libcxx/include/__fwd/bit_reference.h @@ -23,6 +23,12 @@ class __bit_iterator; template struct __size_difference_type_traits; +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz); + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz); + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___FWD_BIT_REFERENCE_H diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp index 7250c49a7ff9528..f40e4444fec2ce0 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp @@ -15,12 +15,14 @@ // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000 +// XFAIL: FROZEN-CXX03-HEADERS-FIXME #include #include #include #include +#include "sized_allocator.h" #include "test_macros.h" #include "test_iterators.h" #include "type_algorithms.h" @@ -36,6 +38,29 @@ struct Test { } }; +TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 100); + } + { + using Alloc = sized_allocator; + std::vector in(199, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 199); + } + { + using Alloc = sized_allocator; + std::vector in(200, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 200); + } + { + using Alloc = sized_allocator; + std::vector in(257, true, Alloc(1)); + assert(std::count(in.begin(), in.end(), true) == 257); + } +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::cpp17_input_iterator_list(), Test()); @@ -51,6 +76,8 @@ TEST_CONSTEXPR_CXX20 bool test() { } } + test_bit_iterator_with_custom_sized_types(); + return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp index 6030bed47ec6a76..b24d3046fb4bb46 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp @@ -29,6 +29,7 @@ #include #include +#include "sized_allocator.h" #include "almost_satisfies_types.h" #include "test_iterators.h" @@ -67,13 +68,13 @@ constexpr void test_iterators() { { // simple test { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; std::same_as auto ret = std::ranges::count(It(a), Sent(It(a + 4)), 3); assert(ret == 1); } { - int a[] = {1, 2, 3, 4}; - auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); + int a[] = {1, 2, 3, 4}; + auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); std::same_as auto ret = std::ranges::count(range, 3); assert(ret == 1); } @@ -83,13 +84,13 @@ constexpr void test_iterators() { // check that an empty range works { std::array a = {}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1); assert(ret == 0); } { std::array a = {}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 1); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 1); assert(ret == 0); } } @@ -98,13 +99,13 @@ constexpr void test_iterators() { // check that a range with a single element works { std::array a = {2}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2); assert(ret == 1); } { std::array a = {2}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 2); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 2); assert(ret == 1); } } @@ -113,13 +114,13 @@ constexpr void test_iterators() { // check that 0 is returned with no match { std::array a = {1, 1, 1}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0); assert(ret == 0); } { std::array a = {1, 1, 1}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 0); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 0); assert(ret == 0); } } @@ -128,13 +129,13 @@ constexpr void test_iterators() { // check that more than one element is counted { std::array a = {3, 3, 4, 3, 3}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3); assert(ret == 4); } { std::array a = {3, 3, 4, 3, 3}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 3); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 3); assert(ret == 4); } } @@ -143,18 +144,41 @@ constexpr void test_iterators() { // check that all elements are counted { std::array a = {5, 5, 5, 5}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5); assert(ret == 4); } { std::array a = {5, 5, 5, 5}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 5); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 5); assert(ret == 4); } } } +TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, true, Alloc(1)); + assert(std::ranges::count(in, true) == 100); + } + { + using Alloc = sized_allocator; + std::vector in(199, true, Alloc(1)); + assert(std::ranges::count(in, true) == 199); + } + { + using Alloc = sized_allocator; + std::vector in(200, true, Alloc(1)); + assert(std::ranges::count(in, true) == 200); + } + { + using Alloc = sized_allocator; + std::vector in(257, true, Alloc(1)); + assert(std::ranges::count(in, true) == 257); + } +} + constexpr bool test() { test_iterators(); test_iterators(); @@ -167,12 +191,12 @@ constexpr bool test() { { // check that projections are used properly and that they are called with the iterator directly { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; auto ret = std::ranges::count(a, a + 4, a + 3, [](int& i) { return &i; }); assert(ret == 1); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; auto ret = std::ranges::count(a, a + 3, [](int& i) { return &i; }); assert(ret == 1); } @@ -180,8 +204,10 @@ constexpr bool test() { { // check that std::invoke is used - struct S { int i; }; - S a[] = { S{1}, S{3}, S{2} }; + struct S { + int i; + }; + S a[] = {S{1}, S{3}, S{2}}; std::same_as auto ret = std::ranges::count(a, 4, &S::i); assert(ret == 0); } @@ -189,16 +215,22 @@ constexpr bool test() { { // count invocations of the projection { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::count(a, a + 4, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::count(a, a + 4, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == 1); assert(projection_count == 4); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::count(a, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::count(a, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == 1); assert(projection_count == 4); } @@ -208,7 +240,7 @@ constexpr bool test() { // check that an immobile type works struct NonMovable { NonMovable(const NonMovable&) = delete; - NonMovable(NonMovable&&) = delete; + NonMovable(NonMovable&&) = delete; constexpr NonMovable(int i_) : i(i_) {} int i; @@ -216,12 +248,12 @@ constexpr bool test() { }; { NonMovable a[] = {9, 8, 4, 3}; - auto ret = std::ranges::count(a, a + 4, NonMovable(8)); + auto ret = std::ranges::count(a, a + 4, NonMovable(8)); assert(ret == 1); } { NonMovable a[] = {9, 8, 4, 3}; - auto ret = std::ranges::count(a, NonMovable(8)); + auto ret = std::ranges::count(a, NonMovable(8)); assert(ret == 1); } } @@ -230,7 +262,7 @@ constexpr bool test() { // check that difference_type is used struct DiffTypeIterator { using difference_type = signed char; - using value_type = int; + using value_type = int; int* it = nullptr; @@ -238,7 +270,10 @@ constexpr bool test() { constexpr DiffTypeIterator(int* i) : it(i) {} constexpr int& operator*() const { return *it; } - constexpr DiffTypeIterator& operator++() { ++it; return *this; } + constexpr DiffTypeIterator& operator++() { + ++it; + return *this; + } constexpr void operator++(int) { ++it; } bool operator==(const DiffTypeIterator&) const = default; @@ -251,7 +286,7 @@ constexpr bool test() { assert(ret == 1); } { - int a[] = {5, 5, 4, 3, 2, 1}; + int a[] = {5, 5, 4, 3, 2, 1}; auto range = std::ranges::subrange(DiffTypeIterator(a), DiffTypeIterator(a + 6)); std::same_as decltype(auto) ret = std::ranges::count(range, 4); assert(ret == 1); @@ -270,6 +305,8 @@ constexpr bool test() { } } + test_bit_iterator_with_custom_sized_types(); + return true; } diff --git a/libcxx/test/support/sized_allocator.h b/libcxx/test/support/sized_allocator.h new file mode 100644 index 000000000000000..a877252e82962c7 --- /dev/null +++ b/libcxx/test/support/sized_allocator.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_SUPPORT_SIZED_ALLOCATOR_H +#define TEST_SUPPORT_SIZED_ALLOCATOR_H + +#include +#include +#include +#include + +#include "test_macros.h" + +template +class sized_allocator { + template + friend class sized_allocator; + +public: + using value_type = T; + using size_type = SIZE_TYPE; + using difference_type = DIFF_TYPE; + using propagate_on_container_swap = std::true_type; + + TEST_CONSTEXPR_CXX20 explicit sized_allocator(int d = 0) : data_(d) {} + + template + TEST_CONSTEXPR_CXX20 sized_allocator(const sized_allocator& a) TEST_NOEXCEPT : data_(a.data_) {} + + TEST_CONSTEXPR_CXX20 T* allocate(size_type n) { + if (n > max_size()) + TEST_THROW(std::bad_array_new_length()); + return std::allocator().allocate(n); + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* p, size_type n) TEST_NOEXCEPT { std::allocator().deallocate(p, n); } + + TEST_CONSTEXPR size_type max_size() const TEST_NOEXCEPT { + return std::numeric_limits::max() / sizeof(value_type); + } + +private: + int data_; + + TEST_CONSTEXPR friend bool operator==(const sized_allocator& a, const sized_allocator& b) { + return a.data_ == b.data_; + } + TEST_CONSTEXPR friend bool operator!=(const sized_allocator& a, const sized_allocator& b) { + return a.data_ != b.data_; + } +}; + +#endif From libcxx-commits at lists.llvm.org Tue Feb 4 20:15:51 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Tue, 04 Feb 2025 20:15:51 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix ambiguous call in {ranges, std}::find (PR #122641) In-Reply-To: Message-ID: <67a2e5f7.a70a0220.ae594.3190@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/122641 >From ff2d21675dc59733151a76190e871c7c5daffc30 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Fri, 10 Jan 2025 15:19:08 -0500 Subject: [PATCH 1/2] Fix ambiguous call in {ranges, std}::find --- libcxx/include/__algorithm/find.h | 10 +-- libcxx/include/__bit/countr.h | 90 ++++++++++++++++--- libcxx/include/__fwd/bit_reference.h | 6 ++ .../alg.nonmodifying/alg.find/find.pass.cpp | 30 +++++++ .../alg.find/ranges.find.pass.cpp | 70 +++++++++++---- libcxx/test/support/sized_allocator.h | 58 ++++++++++++ 6 files changed, 229 insertions(+), 35 deletions(-) create mode 100644 libcxx/test/support/sized_allocator.h diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h index 24b8b2f96443c95..23c38b7d6e80bb0 100644 --- a/libcxx/include/__algorithm/find.h +++ b/libcxx/include/__algorithm/find.h @@ -106,10 +106,10 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty if (__first.__ctz_ != 0) { __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __storage_type __m = std::__middle_mask<__storage_type>(__first.__ctz_, __clz_f - __dn); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); if (__n == __dn) return __first + __n; __n -= __dn; @@ -119,14 +119,14 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) { __storage_type __b = std::__invert_if(*__first.__seg_); if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); } // do last partial word if (__n > 0) { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); } return _It(__first.__seg_, static_cast(__n)); } diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index 2f7571133bd03a3..1035710600d23b0 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -15,6 +15,8 @@ #include <__bit/rotate.h> #include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -38,20 +40,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD return __builtin_ctzll(__x); } -template -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero(_Tp __t) _NOEXCEPT { -#if __has_builtin(__builtin_ctzg) - return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); -#else // __has_builtin(__builtin_ctzg) - if (__t == 0) - return numeric_limits<_Tp>::digits; - if (sizeof(_Tp) <= sizeof(unsigned int)) +#if _LIBCPP_STD_VER >= 17 +// Implementation using constexpr if for C++ standards >= 17 + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) +template ::value, int> = 0> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int __countr_zero_impl(_Tp __t) _NOEXCEPT { + if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_ctz(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { return std::__libcpp_ctz(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_ctz(static_cast(__t)); - else { + } else { int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -60,7 +61,72 @@ template } return __ret + std::__libcpp_ctz(static_cast(__t)); } -#endif // __has_builtin(__builtin_ctzg) +} + +#else +// Equivalent SFINAE-based implementation for older C++ standards < 17 + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) +template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && + sizeof(_Tp) <= sizeof(unsigned long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && + sizeof(_Tp) <= sizeof(unsigned long long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +# if _LIBCPP_STD_VER == 11 + +// Recursive constexpr implementation for C++11 due to limited constexpr support +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + unsigned long long __ull = static_cast(__t); + const unsigned int __ulldigits = numeric_limits::digits; + return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); +} + +# else + +// Loop-based constexpr implementation for C++14 (and non-constexpr for C++03, 98) +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp __t) _NOEXCEPT { + int __ret = 0; + const unsigned int __ulldigits = numeric_limits::digits; + while (static_cast(__t) == 0uLL) { + __ret += __ulldigits; + __t >>= __ulldigits; + } + return __ret + std::__libcpp_ctz(static_cast(__t)); +} + +# endif // _LIBCPP_STD_VER == 11 + +#endif // _LIBCPP_STD_VER >= 17 + +template ::value, int> = 0> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { +#if __has_builtin(__builtin_ctzg) + return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); +#else + return __t != 0 ? __countr_zero_impl(__t) : numeric_limits<_Tp>::digits; +#endif } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__fwd/bit_reference.h b/libcxx/include/__fwd/bit_reference.h index 30462b6ce4c92f8..6932effd95f30e2 100644 --- a/libcxx/include/__fwd/bit_reference.h +++ b/libcxx/include/__fwd/bit_reference.h @@ -10,6 +10,8 @@ #define _LIBCPP___FWD_BIT_REFERENCE_H #include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -23,6 +25,10 @@ class __bit_iterator; template struct __size_difference_type_traits; +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _StorageType +__find_in_masked_range(_StorageType __word, unsigned __ctz, unsigned __clz, bool __find_val); + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___FWD_BIT_REFERENCE_H diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp index c41246522fdebac..6940ff97a0ba5b6 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -14,6 +14,7 @@ // MSVC warning C4389: '==': signed/unsigned mismatch // MSVC warning C4805: '==': unsafe mix of type 'char' and type 'bool' in operation // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4245 /wd4305 /wd4310 /wd4389 /wd4805 +// XFAIL: FROZEN-CXX03-HEADERS-FIXME // @@ -28,6 +29,7 @@ #include #include +#include "sized_allocator.h" #include "test_macros.h" #include "test_iterators.h" #include "type_algorithms.h" @@ -206,6 +208,33 @@ struct TestIntegerPromotions { } }; +TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::integer_types(), TestTypes()); types::for_each(types::integer_types(), TestTypes()); @@ -226,6 +255,7 @@ TEST_CONSTEXPR_CXX20 bool test() { #endif types::for_each(types::integral_types(), TestIntegerPromotions()); + test_bititer_with_custom_sized_types(); return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index 4ae049c3ec00115..a2af568be37c049 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -31,6 +31,7 @@ #include #include "almost_satisfies_types.h" +#include "sized_allocator.h" #include "test_iterators.h" struct NotEqualityComparable {}; @@ -66,14 +67,14 @@ constexpr void test_iterators() { using ValueT = std::iter_value_t; { // simple test { - ValueT a[] = {1, 2, 3, 4}; + ValueT a[] = {1, 2, 3, 4}; std::same_as auto ret = std::ranges::find(It(a), Sent(It(a + 4)), 4); assert(base(ret) == a + 3); assert(*ret == 4); } { - ValueT a[] = {1, 2, 3, 4}; - auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); + ValueT a[] = {1, 2, 3, 4}; + auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); std::same_as auto ret = std::ranges::find(range, 4); assert(base(ret) == a + 3); assert(*ret == 4); @@ -83,13 +84,13 @@ constexpr void test_iterators() { { // check that an empty range works { std::array a = {}; - auto ret = std::ranges::find(It(a.data()), Sent(It(a.data())), 1); + auto ret = std::ranges::find(It(a.data()), Sent(It(a.data())), 1); assert(base(ret) == a.data()); } { std::array a = {}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data()))); - auto ret = std::ranges::find(range, 1); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data()))); + auto ret = std::ranges::find(range, 1); assert(base(ret) == a.data()); } } @@ -97,12 +98,12 @@ constexpr void test_iterators() { { // check that last is returned with no match { ValueT a[] = {1, 1, 1}; - auto ret = std::ranges::find(a, a + 3, 0); + auto ret = std::ranges::find(a, a + 3, 0); assert(ret == a + 3); } { ValueT a[] = {1, 1, 1}; - auto ret = std::ranges::find(a, 0); + auto ret = std::ranges::find(a, 0); assert(ret == a + 3); } } @@ -120,6 +121,33 @@ class TriviallyComparable { bool operator==(const TriviallyComparable&) const = default; }; +constexpr void test_bititer_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } +} + constexpr bool test() { types::for_each(types::type_list, TriviallyComparable>{}, [] { @@ -148,7 +176,7 @@ constexpr bool test() { int comp; int other; }; - S a[] = { {0, 0}, {0, 2}, {0, 1} }; + S a[] = {{0, 0}, {0, 2}, {0, 1}}; auto ret = std::ranges::find(a, 0, &S::comp); assert(ret == a); assert(ret->comp == 0); @@ -159,7 +187,7 @@ constexpr bool test() { int comp; int other; }; - S a[] = { {0, 0}, {0, 2}, {0, 1} }; + S a[] = {{0, 0}, {0, 2}, {0, 1}}; auto ret = std::ranges::find(a, a + 3, 0, &S::comp); assert(ret == a); assert(ret->comp == 0); @@ -169,7 +197,7 @@ constexpr bool test() { { // check that an iterator is returned with a borrowing range - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; std::same_as auto ret = std::ranges::find(std::views::all(a), 1); assert(ret == a); assert(*ret == 1); @@ -178,23 +206,31 @@ constexpr bool test() { { // count invocations of the projection { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::find(a, a + 4, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::find(a, a + 4, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == a + 1); assert(*ret == 2); assert(projection_count == 2); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::find(a, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::find(a, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == a + 1); assert(*ret == 2); assert(projection_count == 2); } } + test_bititer_with_custom_sized_types(); + return true; } @@ -210,9 +246,7 @@ class Comparable { return size; }()) {} - bool operator==(const Comparable& other) const { - return comparable_data[other.index_] == comparable_data[index_]; - } + bool operator==(const Comparable& other) const { return comparable_data[other.index_] == comparable_data[index_]; } friend bool operator==(const Comparable& lhs, long long rhs) { return comparable_data[lhs.index_] == rhs; } }; diff --git a/libcxx/test/support/sized_allocator.h b/libcxx/test/support/sized_allocator.h new file mode 100644 index 000000000000000..a877252e82962c7 --- /dev/null +++ b/libcxx/test/support/sized_allocator.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_SUPPORT_SIZED_ALLOCATOR_H +#define TEST_SUPPORT_SIZED_ALLOCATOR_H + +#include +#include +#include +#include + +#include "test_macros.h" + +template +class sized_allocator { + template + friend class sized_allocator; + +public: + using value_type = T; + using size_type = SIZE_TYPE; + using difference_type = DIFF_TYPE; + using propagate_on_container_swap = std::true_type; + + TEST_CONSTEXPR_CXX20 explicit sized_allocator(int d = 0) : data_(d) {} + + template + TEST_CONSTEXPR_CXX20 sized_allocator(const sized_allocator& a) TEST_NOEXCEPT : data_(a.data_) {} + + TEST_CONSTEXPR_CXX20 T* allocate(size_type n) { + if (n > max_size()) + TEST_THROW(std::bad_array_new_length()); + return std::allocator().allocate(n); + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* p, size_type n) TEST_NOEXCEPT { std::allocator().deallocate(p, n); } + + TEST_CONSTEXPR size_type max_size() const TEST_NOEXCEPT { + return std::numeric_limits::max() / sizeof(value_type); + } + +private: + int data_; + + TEST_CONSTEXPR friend bool operator==(const sized_allocator& a, const sized_allocator& b) { + return a.data_ == b.data_; + } + TEST_CONSTEXPR friend bool operator!=(const sized_allocator& a, const sized_allocator& b) { + return a.data_ != b.data_; + } +}; + +#endif >From c5c8107a0167649eaab50680eb2dc3d53da0f7c6 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Wed, 15 Jan 2025 19:11:16 -0500 Subject: [PATCH 2/2] Refactor --- libcxx/include/__algorithm/find.h | 2 +- libcxx/include/__bit/countr.h | 49 +++++++------------ libcxx/include/__bit_reference | 32 ++++++++++++ libcxx/include/__fwd/bit_reference.h | 10 ++-- .../alg.nonmodifying/alg.find/find.pass.cpp | 8 +-- .../alg.find/ranges.find.pass.cpp | 8 +-- 6 files changed, 64 insertions(+), 45 deletions(-) diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h index 23c38b7d6e80bb0..a7d9374b3a1c89d 100644 --- a/libcxx/include/__algorithm/find.h +++ b/libcxx/include/__algorithm/find.h @@ -106,7 +106,7 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty if (__first.__ctz_ != 0) { __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = std::__middle_mask<__storage_type>(__first.__ctz_, __clz_f - __dn); + __storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index 1035710600d23b0..fe95e9752a9842b 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -40,12 +40,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD return __builtin_ctzll(__x); } -#if _LIBCPP_STD_VER >= 17 -// Implementation using constexpr if for C++ standards >= 17 +#ifndef _LIBCPP_CXX03_LANG +// constexpr implementation for C++11 and later -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) +// Precondition: __t != 0 (the caller __countr_zero handles __t == 0 as a special case) template ::value, int> = 0> -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int __countr_zero_impl(_Tp __t) _NOEXCEPT { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr int __countr_zero_impl(_Tp __t) _NOEXCEPT { if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_ctz(static_cast(__t)); } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { @@ -53,6 +53,12 @@ template ::value, int> = 0> } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_ctz(static_cast(__t)); } else { +# if _LIBCPP_STD_VER == 11 + // A recursive constexpr implementation for C++11 + unsigned long long __ull = static_cast(__t); + const unsigned int __ulldigits = numeric_limits::digits; + return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); +# else int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -61,52 +67,35 @@ template ::value, int> = 0> } return __ret + std::__libcpp_ctz(static_cast(__t)); } +#endif // _LIBCPP_STD_VER == 11 } #else -// Equivalent SFINAE-based implementation for older C++ standards < 17 +// Equivalent implementation using SFINAE-based overloading for C++03 -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { return std::__libcpp_ctz(static_cast(__t)); } -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && sizeof(_Tp) <= sizeof(unsigned long), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { return std::__libcpp_ctz(static_cast(__t)); } -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && sizeof(_Tp) <= sizeof(unsigned long long), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { return std::__libcpp_ctz(static_cast(__t)); } -# if _LIBCPP_STD_VER == 11 - -// Recursive constexpr implementation for C++11 due to limited constexpr support -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) -template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { - unsigned long long __ull = static_cast(__t); - const unsigned int __ulldigits = numeric_limits::digits; - return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); -} - -# else - -// Loop-based constexpr implementation for C++14 (and non-constexpr for C++03, 98) -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -116,16 +105,14 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp _ return __ret + std::__libcpp_ctz(static_cast(__t)); } -# endif // _LIBCPP_STD_VER == 11 - -#endif // _LIBCPP_STD_VER >= 17 +#endif // _LIBCPP_CXX03_LANG template ::value, int> = 0> [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { #if __has_builtin(__builtin_ctzg) return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); #else - return __t != 0 ? __countr_zero_impl(__t) : numeric_limits<_Tp>::digits; + return __t != 0 ? std::__countr_zero_impl(__t) : numeric_limits<_Tp>::digits; #endif } diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c398059..6210db5420c7ca9 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -14,7 +14,9 @@ #include <__algorithm/copy_backward.h> #include <__algorithm/copy_n.h> #include <__algorithm/min.h> +#include <__assert> #include <__bit/countr.h> +#include <__bit/invert_if.h> #include <__compare/ordering.h> #include <__config> #include <__cstddef/ptrdiff_t.h> @@ -25,9 +27,11 @@ #include <__memory/pointer_traits.h> #include <__type_traits/conditional.h> #include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_unsigned.h> #include <__type_traits/void_t.h> #include <__utility/pair.h> #include <__utility/swap.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -58,6 +62,34 @@ struct __size_difference_type_traits<_Cp, __void_t +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz) { + static_assert(is_unsigned<_StorageType>::value, "__trailing_mask only works with unsigned types"); + return static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) { + static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types"); + return static_cast<_StorageType>( + static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz) & + std::__trailing_mask<_StorageType>(__clz)); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unsigned +__find_in_masked_range(_StoragePointer __word, unsigned __clz, unsigned __ctz) { + static_assert(is_unsigned::element_type>::value, + "__find_in_masked_range must be called with unsigned types"); + using _StorageType = typename pointer_traits<_StoragePointer>::element_type; + _LIBCPP_ASSERT_VALID_INPUT_RANGE( + __ctz + __clz < sizeof(_StorageType) * CHAR_BIT, "__find_in_masked_range called with invalid range"); + _StorageType __m = static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz) & + static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz); + _StorageType __b = std::__invert_if(*__word) & __m; + return static_cast(std::__countr_zero(__b)); +} + template ::value> class __bit_reference { using __storage_type _LIBCPP_NODEBUG = typename _Cp::__storage_type; diff --git a/libcxx/include/__fwd/bit_reference.h b/libcxx/include/__fwd/bit_reference.h index 6932effd95f30e2..220366351ba7523 100644 --- a/libcxx/include/__fwd/bit_reference.h +++ b/libcxx/include/__fwd/bit_reference.h @@ -10,8 +10,6 @@ #define _LIBCPP___FWD_BIT_REFERENCE_H #include <__config> -#include <__type_traits/enable_if.h> -#include <__type_traits/is_unsigned.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -25,9 +23,11 @@ class __bit_iterator; template struct __size_difference_type_traits; -template ::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _StorageType -__find_in_masked_range(_StorageType __word, unsigned __ctz, unsigned __clz, bool __find_val); +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz); + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz); _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp index 6940ff97a0ba5b6..599b6355af565b1 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -208,7 +208,7 @@ struct TestIntegerPromotions { } }; -TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { +TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { { using Alloc = sized_allocator; std::vector in(100, false, Alloc(1)); @@ -217,7 +217,7 @@ TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(199, false, Alloc(1)); in[in.size() - 2] = true; assert(std::find(in.begin(), in.end(), true) == in.end() - 2); } @@ -229,7 +229,7 @@ TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(257, false, Alloc(1)); in[in.size() - 2] = true; assert(std::find(in.begin(), in.end(), true) == in.end() - 2); } @@ -255,7 +255,7 @@ TEST_CONSTEXPR_CXX20 bool test() { #endif types::for_each(types::integral_types(), TestIntegerPromotions()); - test_bititer_with_custom_sized_types(); + test_bit_iterator_with_custom_sized_types(); return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index a2af568be37c049..d596e3a5c7970b8 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -121,7 +121,7 @@ class TriviallyComparable { bool operator==(const TriviallyComparable&) const = default; }; -constexpr void test_bititer_with_custom_sized_types() { +constexpr void test_bit_iterator_with_custom_sized_types() { { using Alloc = sized_allocator; std::vector in(100, false, Alloc(1)); @@ -130,7 +130,7 @@ constexpr void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(199, false, Alloc(1)); in[in.size() - 2] = true; assert(std::ranges::find(in, true) == in.end() - 2); } @@ -142,7 +142,7 @@ constexpr void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(257, false, Alloc(1)); in[in.size() - 2] = true; assert(std::ranges::find(in, true) == in.end() - 2); } @@ -229,7 +229,7 @@ constexpr bool test() { } } - test_bititer_with_custom_sized_types(); + test_bit_iterator_with_custom_sized_types(); return true; } From libcxx-commits at lists.llvm.org Tue Feb 4 20:19:01 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Tue, 04 Feb 2025 20:19:01 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix ambiguous call in {ranges, std}::find (PR #122641) In-Reply-To: Message-ID: <67a2e6b5.050a0220.14d7d1.6060@mx.google.com> github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning:
You can test this locally with the following command: ``````````bash git-clang-format --diff 048f533244d537a1451ab2d2979faa762252d37d c5c8107a0167649eaab50680eb2dc3d53da0f7c6 --extensions ,cpp,h -- libcxx/test/support/sized_allocator.h libcxx/include/__algorithm/find.h libcxx/include/__bit/countr.h libcxx/include/__bit_reference libcxx/include/__fwd/bit_reference.h libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp ``````````
View the diff from clang-format here. ``````````diff diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index fe95e9752a..abed351fc4 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -53,12 +53,12 @@ template ::value, int> = 0> } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_ctz(static_cast(__t)); } else { -# if _LIBCPP_STD_VER == 11 +# if _LIBCPP_STD_VER == 11 // A recursive constexpr implementation for C++11 unsigned long long __ull = static_cast(__t); const unsigned int __ulldigits = numeric_limits::digits; return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); -# else +# else int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -67,8 +67,8 @@ template ::value, int> = 0> } return __ret + std::__libcpp_ctz(static_cast(__t)); } -#endif // _LIBCPP_STD_VER == 11 -} +# endif // _LIBCPP_STD_VER == 11 + } #else // Equivalent implementation using SFINAE-based overloading for C++03 @@ -107,14 +107,14 @@ _LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { #endif // _LIBCPP_CXX03_LANG -template ::value, int> = 0> -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { + template ::value, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { #if __has_builtin(__builtin_ctzg) - return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); + return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); #else return __t != 0 ? std::__countr_zero_impl(__t) : numeric_limits<_Tp>::digits; #endif -} + } #if _LIBCPP_STD_VER >= 20 ``````````
https://github.com/llvm/llvm-project/pull/122641 From libcxx-commits at lists.llvm.org Tue Feb 4 20:21:57 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Tue, 04 Feb 2025 20:21:57 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix ambiguous call in {ranges, std}::find (PR #122641) In-Reply-To: Message-ID: <67a2e765.170a0220.1c7d3b.0924@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/122641 >From ff2d21675dc59733151a76190e871c7c5daffc30 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Fri, 10 Jan 2025 15:19:08 -0500 Subject: [PATCH 1/2] Fix ambiguous call in {ranges, std}::find --- libcxx/include/__algorithm/find.h | 10 +-- libcxx/include/__bit/countr.h | 90 ++++++++++++++++--- libcxx/include/__fwd/bit_reference.h | 6 ++ .../alg.nonmodifying/alg.find/find.pass.cpp | 30 +++++++ .../alg.find/ranges.find.pass.cpp | 70 +++++++++++---- libcxx/test/support/sized_allocator.h | 58 ++++++++++++ 6 files changed, 229 insertions(+), 35 deletions(-) create mode 100644 libcxx/test/support/sized_allocator.h diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h index 24b8b2f96443c95..23c38b7d6e80bb0 100644 --- a/libcxx/include/__algorithm/find.h +++ b/libcxx/include/__algorithm/find.h @@ -106,10 +106,10 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty if (__first.__ctz_ != 0) { __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __storage_type __m = std::__middle_mask<__storage_type>(__first.__ctz_, __clz_f - __dn); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); if (__n == __dn) return __first + __n; __n -= __dn; @@ -119,14 +119,14 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) { __storage_type __b = std::__invert_if(*__first.__seg_); if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); } // do last partial word if (__n > 0) { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); } return _It(__first.__seg_, static_cast(__n)); } diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index 2f7571133bd03a3..1035710600d23b0 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -15,6 +15,8 @@ #include <__bit/rotate.h> #include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -38,20 +40,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD return __builtin_ctzll(__x); } -template -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero(_Tp __t) _NOEXCEPT { -#if __has_builtin(__builtin_ctzg) - return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); -#else // __has_builtin(__builtin_ctzg) - if (__t == 0) - return numeric_limits<_Tp>::digits; - if (sizeof(_Tp) <= sizeof(unsigned int)) +#if _LIBCPP_STD_VER >= 17 +// Implementation using constexpr if for C++ standards >= 17 + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) +template ::value, int> = 0> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int __countr_zero_impl(_Tp __t) _NOEXCEPT { + if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_ctz(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { return std::__libcpp_ctz(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_ctz(static_cast(__t)); - else { + } else { int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -60,7 +61,72 @@ template } return __ret + std::__libcpp_ctz(static_cast(__t)); } -#endif // __has_builtin(__builtin_ctzg) +} + +#else +// Equivalent SFINAE-based implementation for older C++ standards < 17 + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) +template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && + sizeof(_Tp) <= sizeof(unsigned long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && + sizeof(_Tp) <= sizeof(unsigned long long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +# if _LIBCPP_STD_VER == 11 + +// Recursive constexpr implementation for C++11 due to limited constexpr support +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + unsigned long long __ull = static_cast(__t); + const unsigned int __ulldigits = numeric_limits::digits; + return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); +} + +# else + +// Loop-based constexpr implementation for C++14 (and non-constexpr for C++03, 98) +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp __t) _NOEXCEPT { + int __ret = 0; + const unsigned int __ulldigits = numeric_limits::digits; + while (static_cast(__t) == 0uLL) { + __ret += __ulldigits; + __t >>= __ulldigits; + } + return __ret + std::__libcpp_ctz(static_cast(__t)); +} + +# endif // _LIBCPP_STD_VER == 11 + +#endif // _LIBCPP_STD_VER >= 17 + +template ::value, int> = 0> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { +#if __has_builtin(__builtin_ctzg) + return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); +#else + return __t != 0 ? __countr_zero_impl(__t) : numeric_limits<_Tp>::digits; +#endif } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__fwd/bit_reference.h b/libcxx/include/__fwd/bit_reference.h index 30462b6ce4c92f8..6932effd95f30e2 100644 --- a/libcxx/include/__fwd/bit_reference.h +++ b/libcxx/include/__fwd/bit_reference.h @@ -10,6 +10,8 @@ #define _LIBCPP___FWD_BIT_REFERENCE_H #include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -23,6 +25,10 @@ class __bit_iterator; template struct __size_difference_type_traits; +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _StorageType +__find_in_masked_range(_StorageType __word, unsigned __ctz, unsigned __clz, bool __find_val); + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___FWD_BIT_REFERENCE_H diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp index c41246522fdebac..6940ff97a0ba5b6 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -14,6 +14,7 @@ // MSVC warning C4389: '==': signed/unsigned mismatch // MSVC warning C4805: '==': unsafe mix of type 'char' and type 'bool' in operation // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4245 /wd4305 /wd4310 /wd4389 /wd4805 +// XFAIL: FROZEN-CXX03-HEADERS-FIXME // @@ -28,6 +29,7 @@ #include #include +#include "sized_allocator.h" #include "test_macros.h" #include "test_iterators.h" #include "type_algorithms.h" @@ -206,6 +208,33 @@ struct TestIntegerPromotions { } }; +TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::integer_types(), TestTypes()); types::for_each(types::integer_types(), TestTypes()); @@ -226,6 +255,7 @@ TEST_CONSTEXPR_CXX20 bool test() { #endif types::for_each(types::integral_types(), TestIntegerPromotions()); + test_bititer_with_custom_sized_types(); return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index 4ae049c3ec00115..a2af568be37c049 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -31,6 +31,7 @@ #include #include "almost_satisfies_types.h" +#include "sized_allocator.h" #include "test_iterators.h" struct NotEqualityComparable {}; @@ -66,14 +67,14 @@ constexpr void test_iterators() { using ValueT = std::iter_value_t; { // simple test { - ValueT a[] = {1, 2, 3, 4}; + ValueT a[] = {1, 2, 3, 4}; std::same_as auto ret = std::ranges::find(It(a), Sent(It(a + 4)), 4); assert(base(ret) == a + 3); assert(*ret == 4); } { - ValueT a[] = {1, 2, 3, 4}; - auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); + ValueT a[] = {1, 2, 3, 4}; + auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); std::same_as auto ret = std::ranges::find(range, 4); assert(base(ret) == a + 3); assert(*ret == 4); @@ -83,13 +84,13 @@ constexpr void test_iterators() { { // check that an empty range works { std::array a = {}; - auto ret = std::ranges::find(It(a.data()), Sent(It(a.data())), 1); + auto ret = std::ranges::find(It(a.data()), Sent(It(a.data())), 1); assert(base(ret) == a.data()); } { std::array a = {}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data()))); - auto ret = std::ranges::find(range, 1); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data()))); + auto ret = std::ranges::find(range, 1); assert(base(ret) == a.data()); } } @@ -97,12 +98,12 @@ constexpr void test_iterators() { { // check that last is returned with no match { ValueT a[] = {1, 1, 1}; - auto ret = std::ranges::find(a, a + 3, 0); + auto ret = std::ranges::find(a, a + 3, 0); assert(ret == a + 3); } { ValueT a[] = {1, 1, 1}; - auto ret = std::ranges::find(a, 0); + auto ret = std::ranges::find(a, 0); assert(ret == a + 3); } } @@ -120,6 +121,33 @@ class TriviallyComparable { bool operator==(const TriviallyComparable&) const = default; }; +constexpr void test_bititer_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } +} + constexpr bool test() { types::for_each(types::type_list, TriviallyComparable>{}, [] { @@ -148,7 +176,7 @@ constexpr bool test() { int comp; int other; }; - S a[] = { {0, 0}, {0, 2}, {0, 1} }; + S a[] = {{0, 0}, {0, 2}, {0, 1}}; auto ret = std::ranges::find(a, 0, &S::comp); assert(ret == a); assert(ret->comp == 0); @@ -159,7 +187,7 @@ constexpr bool test() { int comp; int other; }; - S a[] = { {0, 0}, {0, 2}, {0, 1} }; + S a[] = {{0, 0}, {0, 2}, {0, 1}}; auto ret = std::ranges::find(a, a + 3, 0, &S::comp); assert(ret == a); assert(ret->comp == 0); @@ -169,7 +197,7 @@ constexpr bool test() { { // check that an iterator is returned with a borrowing range - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; std::same_as auto ret = std::ranges::find(std::views::all(a), 1); assert(ret == a); assert(*ret == 1); @@ -178,23 +206,31 @@ constexpr bool test() { { // count invocations of the projection { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::find(a, a + 4, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::find(a, a + 4, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == a + 1); assert(*ret == 2); assert(projection_count == 2); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::find(a, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::find(a, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == a + 1); assert(*ret == 2); assert(projection_count == 2); } } + test_bititer_with_custom_sized_types(); + return true; } @@ -210,9 +246,7 @@ class Comparable { return size; }()) {} - bool operator==(const Comparable& other) const { - return comparable_data[other.index_] == comparable_data[index_]; - } + bool operator==(const Comparable& other) const { return comparable_data[other.index_] == comparable_data[index_]; } friend bool operator==(const Comparable& lhs, long long rhs) { return comparable_data[lhs.index_] == rhs; } }; diff --git a/libcxx/test/support/sized_allocator.h b/libcxx/test/support/sized_allocator.h new file mode 100644 index 000000000000000..a877252e82962c7 --- /dev/null +++ b/libcxx/test/support/sized_allocator.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_SUPPORT_SIZED_ALLOCATOR_H +#define TEST_SUPPORT_SIZED_ALLOCATOR_H + +#include +#include +#include +#include + +#include "test_macros.h" + +template +class sized_allocator { + template + friend class sized_allocator; + +public: + using value_type = T; + using size_type = SIZE_TYPE; + using difference_type = DIFF_TYPE; + using propagate_on_container_swap = std::true_type; + + TEST_CONSTEXPR_CXX20 explicit sized_allocator(int d = 0) : data_(d) {} + + template + TEST_CONSTEXPR_CXX20 sized_allocator(const sized_allocator& a) TEST_NOEXCEPT : data_(a.data_) {} + + TEST_CONSTEXPR_CXX20 T* allocate(size_type n) { + if (n > max_size()) + TEST_THROW(std::bad_array_new_length()); + return std::allocator().allocate(n); + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* p, size_type n) TEST_NOEXCEPT { std::allocator().deallocate(p, n); } + + TEST_CONSTEXPR size_type max_size() const TEST_NOEXCEPT { + return std::numeric_limits::max() / sizeof(value_type); + } + +private: + int data_; + + TEST_CONSTEXPR friend bool operator==(const sized_allocator& a, const sized_allocator& b) { + return a.data_ == b.data_; + } + TEST_CONSTEXPR friend bool operator!=(const sized_allocator& a, const sized_allocator& b) { + return a.data_ != b.data_; + } +}; + +#endif >From cba1e2c6acd210f16431293aab3860608c9ec695 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Wed, 15 Jan 2025 19:11:16 -0500 Subject: [PATCH 2/2] Refactor --- libcxx/include/__algorithm/find.h | 2 +- libcxx/include/__bit/countr.h | 79 ++++++++----------- libcxx/include/__bit_reference | 32 ++++++++ libcxx/include/__fwd/bit_reference.h | 10 +-- .../alg.nonmodifying/alg.find/find.pass.cpp | 8 +- .../alg.find/ranges.find.pass.cpp | 8 +- 6 files changed, 79 insertions(+), 60 deletions(-) diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h index 23c38b7d6e80bb0..a7d9374b3a1c89d 100644 --- a/libcxx/include/__algorithm/find.h +++ b/libcxx/include/__algorithm/find.h @@ -106,7 +106,7 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty if (__first.__ctz_ != 0) { __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = std::__middle_mask<__storage_type>(__first.__ctz_, __clz_f - __dn); + __storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index 1035710600d23b0..65018a1fd81529a 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -40,12 +40,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD return __builtin_ctzll(__x); } -#if _LIBCPP_STD_VER >= 17 -// Implementation using constexpr if for C++ standards >= 17 +#ifndef _LIBCPP_CXX03_LANG +// constexpr implementation for C++11 and later -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) +// Precondition: __t != 0 (the caller __countr_zero handles __t == 0 as a special case) template ::value, int> = 0> -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int __countr_zero_impl(_Tp __t) _NOEXCEPT { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr int __countr_zero_impl(_Tp __t) _NOEXCEPT { if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_ctz(static_cast(__t)); } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { @@ -53,6 +53,12 @@ template ::value, int> = 0> } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_ctz(static_cast(__t)); } else { +# if _LIBCPP_STD_VER == 11 + // A recursive constexpr implementation for C++11 + unsigned long long __ull = static_cast(__t); + const unsigned int __ulldigits = numeric_limits::digits; + return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); +# else int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -61,52 +67,35 @@ template ::value, int> = 0> } return __ret + std::__libcpp_ctz(static_cast(__t)); } -} +# endif // _LIBCPP_STD_VER == 11 + } #else -// Equivalent SFINAE-based implementation for older C++ standards < 17 +// Equivalent implementation using SFINAE-based overloading for C++03 -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { return std::__libcpp_ctz(static_cast(__t)); } -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && sizeof(_Tp) <= sizeof(unsigned long), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { return std::__libcpp_ctz(static_cast(__t)); } -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && sizeof(_Tp) <= sizeof(unsigned long long), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { return std::__libcpp_ctz(static_cast(__t)); } -# if _LIBCPP_STD_VER == 11 - -// Recursive constexpr implementation for C++11 due to limited constexpr support -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { - unsigned long long __ull = static_cast(__t); - const unsigned int __ulldigits = numeric_limits::digits; - return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); -} - -# else - -// Loop-based constexpr implementation for C++14 (and non-constexpr for C++03, 98) -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) -template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -116,35 +105,33 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp _ return __ret + std::__libcpp_ctz(static_cast(__t)); } -# endif // _LIBCPP_STD_VER == 11 - -#endif // _LIBCPP_STD_VER >= 17 +#endif // _LIBCPP_CXX03_LANG -template ::value, int> = 0> -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { + template ::value, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { #if __has_builtin(__builtin_ctzg) - return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); + return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); #else - return __t != 0 ? __countr_zero_impl(__t) : numeric_limits<_Tp>::digits; + return __t != 0 ? std::__countr_zero_impl(__t) : numeric_limits<_Tp>::digits; #endif -} + } #if _LIBCPP_STD_VER >= 20 -template <__libcpp_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_zero(_Tp __t) noexcept { - return std::__countr_zero(__t); -} + template <__libcpp_unsigned_integer _Tp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_zero(_Tp __t) noexcept { + return std::__countr_zero(__t); + } -template <__libcpp_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_one(_Tp __t) noexcept { - return __t != numeric_limits<_Tp>::max() ? std::countr_zero(static_cast<_Tp>(~__t)) : numeric_limits<_Tp>::digits; -} + template <__libcpp_unsigned_integer _Tp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_one(_Tp __t) noexcept { + return __t != numeric_limits<_Tp>::max() ? std::countr_zero(static_cast<_Tp>(~__t)) : numeric_limits<_Tp>::digits; + } #endif // _LIBCPP_STD_VER >= 20 -_LIBCPP_END_NAMESPACE_STD + _LIBCPP_END_NAMESPACE_STD -_LIBCPP_POP_MACROS + _LIBCPP_POP_MACROS #endif // _LIBCPP___BIT_COUNTR_H diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c398059..6210db5420c7ca9 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -14,7 +14,9 @@ #include <__algorithm/copy_backward.h> #include <__algorithm/copy_n.h> #include <__algorithm/min.h> +#include <__assert> #include <__bit/countr.h> +#include <__bit/invert_if.h> #include <__compare/ordering.h> #include <__config> #include <__cstddef/ptrdiff_t.h> @@ -25,9 +27,11 @@ #include <__memory/pointer_traits.h> #include <__type_traits/conditional.h> #include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_unsigned.h> #include <__type_traits/void_t.h> #include <__utility/pair.h> #include <__utility/swap.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -58,6 +62,34 @@ struct __size_difference_type_traits<_Cp, __void_t +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz) { + static_assert(is_unsigned<_StorageType>::value, "__trailing_mask only works with unsigned types"); + return static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) { + static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types"); + return static_cast<_StorageType>( + static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz) & + std::__trailing_mask<_StorageType>(__clz)); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unsigned +__find_in_masked_range(_StoragePointer __word, unsigned __clz, unsigned __ctz) { + static_assert(is_unsigned::element_type>::value, + "__find_in_masked_range must be called with unsigned types"); + using _StorageType = typename pointer_traits<_StoragePointer>::element_type; + _LIBCPP_ASSERT_VALID_INPUT_RANGE( + __ctz + __clz < sizeof(_StorageType) * CHAR_BIT, "__find_in_masked_range called with invalid range"); + _StorageType __m = static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz) & + static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz); + _StorageType __b = std::__invert_if(*__word) & __m; + return static_cast(std::__countr_zero(__b)); +} + template ::value> class __bit_reference { using __storage_type _LIBCPP_NODEBUG = typename _Cp::__storage_type; diff --git a/libcxx/include/__fwd/bit_reference.h b/libcxx/include/__fwd/bit_reference.h index 6932effd95f30e2..220366351ba7523 100644 --- a/libcxx/include/__fwd/bit_reference.h +++ b/libcxx/include/__fwd/bit_reference.h @@ -10,8 +10,6 @@ #define _LIBCPP___FWD_BIT_REFERENCE_H #include <__config> -#include <__type_traits/enable_if.h> -#include <__type_traits/is_unsigned.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -25,9 +23,11 @@ class __bit_iterator; template struct __size_difference_type_traits; -template ::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _StorageType -__find_in_masked_range(_StorageType __word, unsigned __ctz, unsigned __clz, bool __find_val); +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz); + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz); _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp index 6940ff97a0ba5b6..599b6355af565b1 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -208,7 +208,7 @@ struct TestIntegerPromotions { } }; -TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { +TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { { using Alloc = sized_allocator; std::vector in(100, false, Alloc(1)); @@ -217,7 +217,7 @@ TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(199, false, Alloc(1)); in[in.size() - 2] = true; assert(std::find(in.begin(), in.end(), true) == in.end() - 2); } @@ -229,7 +229,7 @@ TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(257, false, Alloc(1)); in[in.size() - 2] = true; assert(std::find(in.begin(), in.end(), true) == in.end() - 2); } @@ -255,7 +255,7 @@ TEST_CONSTEXPR_CXX20 bool test() { #endif types::for_each(types::integral_types(), TestIntegerPromotions()); - test_bititer_with_custom_sized_types(); + test_bit_iterator_with_custom_sized_types(); return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index a2af568be37c049..d596e3a5c7970b8 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -121,7 +121,7 @@ class TriviallyComparable { bool operator==(const TriviallyComparable&) const = default; }; -constexpr void test_bititer_with_custom_sized_types() { +constexpr void test_bit_iterator_with_custom_sized_types() { { using Alloc = sized_allocator; std::vector in(100, false, Alloc(1)); @@ -130,7 +130,7 @@ constexpr void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(199, false, Alloc(1)); in[in.size() - 2] = true; assert(std::ranges::find(in, true) == in.end() - 2); } @@ -142,7 +142,7 @@ constexpr void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(257, false, Alloc(1)); in[in.size() - 2] = true; assert(std::ranges::find(in, true) == in.end() - 2); } @@ -229,7 +229,7 @@ constexpr bool test() { } } - test_bititer_with_custom_sized_types(); + test_bit_iterator_with_custom_sized_types(); return true; } From libcxx-commits at lists.llvm.org Wed Feb 5 00:11:24 2025 From: libcxx-commits at lists.llvm.org (Petr Hosek via libcxx-commits) Date: Wed, 05 Feb 2025 00:11:24 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Avoid including on arbitrary platforms (PR #125587) In-Reply-To: Message-ID: <67a31d2c.650a0220.364a5a.9345@mx.google.com> petrhosek wrote: This is going to break other platforms supported by LLVM libc, most notably baremetal (for which we don't really have a great detection mechanism since there's no OS). An alternative to using a header would be to store the value of [`LIBCXX_LIBC`](https://github.com/llvm/llvm-project/blob/646d352ab0d0a9cfafa3f2c9c415b5773834ad5b/libcxx/CMakeLists.txt#L231) CMake option in `__config_site` and then use that. This could also eventually replace [`_LIBCPP_HAS_MUSL_LIBC`](https://github.com/llvm/llvm-project/blob/646d352ab0d0a9cfafa3f2c9c415b5773834ad5b/libcxx/include/__config_site.in#L19). https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Wed Feb 5 01:50:49 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Wed, 05 Feb 2025 01:50:49 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a33479.a70a0220.aa7f9.522c@mx.google.com> philnik777 wrote: > The compiler's `-fno-sized-deallocation` flag allows controlling whether delete expressions should use sized delete or not, which is a breaking change for some code, since it changes which `operator delete` gets called without making any changes to the user code. AFAIU, that's the purpose of that flag and that's the reason why it wasn't made the default until recently (upstream). I don't think that's the problem. The sized overload just calls the unsized one by default, so I don't see how that's breaking. My understanding is that the fundamental is that the compiler silently changes to generating calls to functions which may not exist in the runtime yet. That could probably have been solved by using availability information, but most platforms don't have that. > Some users might be in a situation where they don't want their `delete` expressions to resolve differently, but where it is 100% acceptable to call the sized `operator delete` explicitly. In that case, they could pass `-fno-sized-deallocation` yet still call the library function explicitly (after this patch, but not before). In what scenario is that the case? Even if I grant that it's a breaking change because allocation replacements may not be aware of the new overload, this can only result in an allocator/deallocator mismatch at that point, which is always a bad idea. > For availability issues, we have attributes on these declarations: if someone attempts to use a sized `operator delete` while compiling for a target that does not support the functionality, that should be caught at compile-time by these attributes. Do you mean we'd have them if there are back-deployment problems? Because I can't find any. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Wed Feb 5 02:13:46 2025 From: libcxx-commits at lists.llvm.org (Hristo Hristov via libcxx-commits) Date: Wed, 05 Feb 2025 02:13:46 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++][numeric][NFC] Cleanup *Saturation arithmetic* tests (PR #101826) In-Reply-To: Message-ID: <67a339da.170a0220.32872.37df@mx.google.com> https://github.com/Zingam edited https://github.com/llvm/llvm-project/pull/101826 From libcxx-commits at lists.llvm.org Wed Feb 5 02:58:33 2025 From: libcxx-commits at lists.llvm.org (Nhat Nguyen via libcxx-commits) Date: Wed, 05 Feb 2025 02:58:33 -0800 (PST) Subject: [libcxx-commits] [clang] [clang-tools-extra] [libcxx] [llvm] [libc++][ranges] P2542R8: Implement `views::concat` (PR #120920) In-Reply-To: Message-ID: <67a34459.170a0220.291fb.3ab7@mx.google.com> changkhothuychung wrote: @frederick-vs-ja just follow up on this https://github.com/llvm/llvm-project/pull/120920 From libcxx-commits at lists.llvm.org Wed Feb 5 03:47:05 2025 From: libcxx-commits at lists.llvm.org (Peng Liu via libcxx-commits) Date: Wed, 05 Feb 2025 03:47:05 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Fix ambiguous call in {ranges, std}::find (PR #122641) In-Reply-To: Message-ID: <67a34fb9.050a0220.1ad2d9.787d@mx.google.com> https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/122641 >From a39261856c5db543069f7e9205e0a3deed31ab05 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Fri, 10 Jan 2025 15:19:08 -0500 Subject: [PATCH 1/2] Fix ambiguous call in {ranges, std}::find --- libcxx/include/__algorithm/find.h | 10 +-- libcxx/include/__bit/countr.h | 90 ++++++++++++++++--- libcxx/include/__fwd/bit_reference.h | 6 ++ .../alg.nonmodifying/alg.find/find.pass.cpp | 30 +++++++ .../alg.find/ranges.find.pass.cpp | 70 +++++++++++---- libcxx/test/support/sized_allocator.h | 58 ++++++++++++ 6 files changed, 229 insertions(+), 35 deletions(-) create mode 100644 libcxx/test/support/sized_allocator.h diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h index 24b8b2f96443c9..23c38b7d6e80bb 100644 --- a/libcxx/include/__algorithm/find.h +++ b/libcxx/include/__algorithm/find.h @@ -106,10 +106,10 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty if (__first.__ctz_ != 0) { __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __storage_type __m = std::__middle_mask<__storage_type>(__first.__ctz_, __clz_f - __dn); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); if (__n == __dn) return __first + __n; __n -= __dn; @@ -119,14 +119,14 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) { __storage_type __b = std::__invert_if(*__first.__seg_); if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); } // do last partial word if (__n > 0) { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); } return _It(__first.__seg_, static_cast(__n)); } diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index 2f7571133bd03a..1035710600d23b 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -15,6 +15,8 @@ #include <__bit/rotate.h> #include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -38,20 +40,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD return __builtin_ctzll(__x); } -template -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero(_Tp __t) _NOEXCEPT { -#if __has_builtin(__builtin_ctzg) - return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); -#else // __has_builtin(__builtin_ctzg) - if (__t == 0) - return numeric_limits<_Tp>::digits; - if (sizeof(_Tp) <= sizeof(unsigned int)) +#if _LIBCPP_STD_VER >= 17 +// Implementation using constexpr if for C++ standards >= 17 + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) +template ::value, int> = 0> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int __countr_zero_impl(_Tp __t) _NOEXCEPT { + if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_ctz(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { return std::__libcpp_ctz(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_ctz(static_cast(__t)); - else { + } else { int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -60,7 +61,72 @@ template } return __ret + std::__libcpp_ctz(static_cast(__t)); } -#endif // __has_builtin(__builtin_ctzg) +} + +#else +// Equivalent SFINAE-based implementation for older C++ standards < 17 + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) +template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && + sizeof(_Tp) <= sizeof(unsigned long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && + sizeof(_Tp) <= sizeof(unsigned long long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +# if _LIBCPP_STD_VER == 11 + +// Recursive constexpr implementation for C++11 due to limited constexpr support +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + unsigned long long __ull = static_cast(__t); + const unsigned int __ulldigits = numeric_limits::digits; + return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); +} + +# else + +// Loop-based constexpr implementation for C++14 (and non-constexpr for C++03, 98) +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp __t) _NOEXCEPT { + int __ret = 0; + const unsigned int __ulldigits = numeric_limits::digits; + while (static_cast(__t) == 0uLL) { + __ret += __ulldigits; + __t >>= __ulldigits; + } + return __ret + std::__libcpp_ctz(static_cast(__t)); +} + +# endif // _LIBCPP_STD_VER == 11 + +#endif // _LIBCPP_STD_VER >= 17 + +template ::value, int> = 0> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { +#if __has_builtin(__builtin_ctzg) + return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); +#else + return __t != 0 ? __countr_zero_impl(__t) : numeric_limits<_Tp>::digits; +#endif } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__fwd/bit_reference.h b/libcxx/include/__fwd/bit_reference.h index 30462b6ce4c92f..6932effd95f30e 100644 --- a/libcxx/include/__fwd/bit_reference.h +++ b/libcxx/include/__fwd/bit_reference.h @@ -10,6 +10,8 @@ #define _LIBCPP___FWD_BIT_REFERENCE_H #include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -23,6 +25,10 @@ class __bit_iterator; template struct __size_difference_type_traits; +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _StorageType +__find_in_masked_range(_StorageType __word, unsigned __ctz, unsigned __clz, bool __find_val); + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___FWD_BIT_REFERENCE_H diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp index c41246522fdeba..6940ff97a0ba5b 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -14,6 +14,7 @@ // MSVC warning C4389: '==': signed/unsigned mismatch // MSVC warning C4805: '==': unsafe mix of type 'char' and type 'bool' in operation // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4245 /wd4305 /wd4310 /wd4389 /wd4805 +// XFAIL: FROZEN-CXX03-HEADERS-FIXME // @@ -28,6 +29,7 @@ #include #include +#include "sized_allocator.h" #include "test_macros.h" #include "test_iterators.h" #include "type_algorithms.h" @@ -206,6 +208,33 @@ struct TestIntegerPromotions { } }; +TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::integer_types(), TestTypes()); types::for_each(types::integer_types(), TestTypes()); @@ -226,6 +255,7 @@ TEST_CONSTEXPR_CXX20 bool test() { #endif types::for_each(types::integral_types(), TestIntegerPromotions()); + test_bititer_with_custom_sized_types(); return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index 4ae049c3ec0011..a2af568be37c04 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -31,6 +31,7 @@ #include #include "almost_satisfies_types.h" +#include "sized_allocator.h" #include "test_iterators.h" struct NotEqualityComparable {}; @@ -66,14 +67,14 @@ constexpr void test_iterators() { using ValueT = std::iter_value_t; { // simple test { - ValueT a[] = {1, 2, 3, 4}; + ValueT a[] = {1, 2, 3, 4}; std::same_as auto ret = std::ranges::find(It(a), Sent(It(a + 4)), 4); assert(base(ret) == a + 3); assert(*ret == 4); } { - ValueT a[] = {1, 2, 3, 4}; - auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); + ValueT a[] = {1, 2, 3, 4}; + auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); std::same_as auto ret = std::ranges::find(range, 4); assert(base(ret) == a + 3); assert(*ret == 4); @@ -83,13 +84,13 @@ constexpr void test_iterators() { { // check that an empty range works { std::array a = {}; - auto ret = std::ranges::find(It(a.data()), Sent(It(a.data())), 1); + auto ret = std::ranges::find(It(a.data()), Sent(It(a.data())), 1); assert(base(ret) == a.data()); } { std::array a = {}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data()))); - auto ret = std::ranges::find(range, 1); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data()))); + auto ret = std::ranges::find(range, 1); assert(base(ret) == a.data()); } } @@ -97,12 +98,12 @@ constexpr void test_iterators() { { // check that last is returned with no match { ValueT a[] = {1, 1, 1}; - auto ret = std::ranges::find(a, a + 3, 0); + auto ret = std::ranges::find(a, a + 3, 0); assert(ret == a + 3); } { ValueT a[] = {1, 1, 1}; - auto ret = std::ranges::find(a, 0); + auto ret = std::ranges::find(a, 0); assert(ret == a + 3); } } @@ -120,6 +121,33 @@ class TriviallyComparable { bool operator==(const TriviallyComparable&) const = default; }; +constexpr void test_bititer_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } +} + constexpr bool test() { types::for_each(types::type_list, TriviallyComparable>{}, [] { @@ -148,7 +176,7 @@ constexpr bool test() { int comp; int other; }; - S a[] = { {0, 0}, {0, 2}, {0, 1} }; + S a[] = {{0, 0}, {0, 2}, {0, 1}}; auto ret = std::ranges::find(a, 0, &S::comp); assert(ret == a); assert(ret->comp == 0); @@ -159,7 +187,7 @@ constexpr bool test() { int comp; int other; }; - S a[] = { {0, 0}, {0, 2}, {0, 1} }; + S a[] = {{0, 0}, {0, 2}, {0, 1}}; auto ret = std::ranges::find(a, a + 3, 0, &S::comp); assert(ret == a); assert(ret->comp == 0); @@ -169,7 +197,7 @@ constexpr bool test() { { // check that an iterator is returned with a borrowing range - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; std::same_as auto ret = std::ranges::find(std::views::all(a), 1); assert(ret == a); assert(*ret == 1); @@ -178,23 +206,31 @@ constexpr bool test() { { // count invocations of the projection { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::find(a, a + 4, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::find(a, a + 4, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == a + 1); assert(*ret == 2); assert(projection_count == 2); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::find(a, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::find(a, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == a + 1); assert(*ret == 2); assert(projection_count == 2); } } + test_bititer_with_custom_sized_types(); + return true; } @@ -210,9 +246,7 @@ class Comparable { return size; }()) {} - bool operator==(const Comparable& other) const { - return comparable_data[other.index_] == comparable_data[index_]; - } + bool operator==(const Comparable& other) const { return comparable_data[other.index_] == comparable_data[index_]; } friend bool operator==(const Comparable& lhs, long long rhs) { return comparable_data[lhs.index_] == rhs; } }; diff --git a/libcxx/test/support/sized_allocator.h b/libcxx/test/support/sized_allocator.h new file mode 100644 index 00000000000000..a877252e82962c --- /dev/null +++ b/libcxx/test/support/sized_allocator.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_SUPPORT_SIZED_ALLOCATOR_H +#define TEST_SUPPORT_SIZED_ALLOCATOR_H + +#include +#include +#include +#include + +#include "test_macros.h" + +template +class sized_allocator { + template + friend class sized_allocator; + +public: + using value_type = T; + using size_type = SIZE_TYPE; + using difference_type = DIFF_TYPE; + using propagate_on_container_swap = std::true_type; + + TEST_CONSTEXPR_CXX20 explicit sized_allocator(int d = 0) : data_(d) {} + + template + TEST_CONSTEXPR_CXX20 sized_allocator(const sized_allocator& a) TEST_NOEXCEPT : data_(a.data_) {} + + TEST_CONSTEXPR_CXX20 T* allocate(size_type n) { + if (n > max_size()) + TEST_THROW(std::bad_array_new_length()); + return std::allocator().allocate(n); + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* p, size_type n) TEST_NOEXCEPT { std::allocator().deallocate(p, n); } + + TEST_CONSTEXPR size_type max_size() const TEST_NOEXCEPT { + return std::numeric_limits::max() / sizeof(value_type); + } + +private: + int data_; + + TEST_CONSTEXPR friend bool operator==(const sized_allocator& a, const sized_allocator& b) { + return a.data_ == b.data_; + } + TEST_CONSTEXPR friend bool operator!=(const sized_allocator& a, const sized_allocator& b) { + return a.data_ != b.data_; + } +}; + +#endif >From c5f6eb1087b2bed24f6f5a4cf2d19ed9af56f997 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Wed, 15 Jan 2025 19:11:16 -0500 Subject: [PATCH 2/2] Refactor --- libcxx/include/__algorithm/find.h | 2 +- libcxx/include/__bit/countr.h | 79 ++++++++----------- libcxx/include/__bit_reference | 32 ++++++++ libcxx/include/__fwd/bit_reference.h | 10 +-- .../alg.nonmodifying/alg.find/find.pass.cpp | 8 +- .../alg.find/ranges.find.pass.cpp | 8 +- 6 files changed, 79 insertions(+), 60 deletions(-) diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h index 23c38b7d6e80bb..a7d9374b3a1c89 100644 --- a/libcxx/include/__algorithm/find.h +++ b/libcxx/include/__algorithm/find.h @@ -106,7 +106,7 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty if (__first.__ctz_ != 0) { __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = std::__middle_mask<__storage_type>(__first.__ctz_, __clz_f - __dn); + __storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index 1035710600d23b..65018a1fd81529 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -40,12 +40,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD return __builtin_ctzll(__x); } -#if _LIBCPP_STD_VER >= 17 -// Implementation using constexpr if for C++ standards >= 17 +#ifndef _LIBCPP_CXX03_LANG +// constexpr implementation for C++11 and later -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) +// Precondition: __t != 0 (the caller __countr_zero handles __t == 0 as a special case) template ::value, int> = 0> -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int __countr_zero_impl(_Tp __t) _NOEXCEPT { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr int __countr_zero_impl(_Tp __t) _NOEXCEPT { if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_ctz(static_cast(__t)); } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { @@ -53,6 +53,12 @@ template ::value, int> = 0> } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_ctz(static_cast(__t)); } else { +# if _LIBCPP_STD_VER == 11 + // A recursive constexpr implementation for C++11 + unsigned long long __ull = static_cast(__t); + const unsigned int __ulldigits = numeric_limits::digits; + return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); +# else int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -61,52 +67,35 @@ template ::value, int> = 0> } return __ret + std::__libcpp_ctz(static_cast(__t)); } -} +# endif // _LIBCPP_STD_VER == 11 + } #else -// Equivalent SFINAE-based implementation for older C++ standards < 17 +// Equivalent implementation using SFINAE-based overloading for C++03 -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { return std::__libcpp_ctz(static_cast(__t)); } -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && sizeof(_Tp) <= sizeof(unsigned long), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { return std::__libcpp_ctz(static_cast(__t)); } -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && sizeof(_Tp) <= sizeof(unsigned long long), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { return std::__libcpp_ctz(static_cast(__t)); } -# if _LIBCPP_STD_VER == 11 - -// Recursive constexpr implementation for C++11 due to limited constexpr support -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { - unsigned long long __ull = static_cast(__t); - const unsigned int __ulldigits = numeric_limits::digits; - return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); -} - -# else - -// Loop-based constexpr implementation for C++14 (and non-constexpr for C++03, 98) -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) -template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) _NOEXCEPT { int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -116,35 +105,33 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp _ return __ret + std::__libcpp_ctz(static_cast(__t)); } -# endif // _LIBCPP_STD_VER == 11 - -#endif // _LIBCPP_STD_VER >= 17 +#endif // _LIBCPP_CXX03_LANG -template ::value, int> = 0> -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { + template ::value, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { #if __has_builtin(__builtin_ctzg) - return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); + return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); #else - return __t != 0 ? __countr_zero_impl(__t) : numeric_limits<_Tp>::digits; + return __t != 0 ? std::__countr_zero_impl(__t) : numeric_limits<_Tp>::digits; #endif -} + } #if _LIBCPP_STD_VER >= 20 -template <__libcpp_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_zero(_Tp __t) noexcept { - return std::__countr_zero(__t); -} + template <__libcpp_unsigned_integer _Tp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_zero(_Tp __t) noexcept { + return std::__countr_zero(__t); + } -template <__libcpp_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_one(_Tp __t) noexcept { - return __t != numeric_limits<_Tp>::max() ? std::countr_zero(static_cast<_Tp>(~__t)) : numeric_limits<_Tp>::digits; -} + template <__libcpp_unsigned_integer _Tp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_one(_Tp __t) noexcept { + return __t != numeric_limits<_Tp>::max() ? std::countr_zero(static_cast<_Tp>(~__t)) : numeric_limits<_Tp>::digits; + } #endif // _LIBCPP_STD_VER >= 20 -_LIBCPP_END_NAMESPACE_STD + _LIBCPP_END_NAMESPACE_STD -_LIBCPP_POP_MACROS + _LIBCPP_POP_MACROS #endif // _LIBCPP___BIT_COUNTR_H diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index bb8d4725c39805..6210db5420c7ca 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -14,7 +14,9 @@ #include <__algorithm/copy_backward.h> #include <__algorithm/copy_n.h> #include <__algorithm/min.h> +#include <__assert> #include <__bit/countr.h> +#include <__bit/invert_if.h> #include <__compare/ordering.h> #include <__config> #include <__cstddef/ptrdiff_t.h> @@ -25,9 +27,11 @@ #include <__memory/pointer_traits.h> #include <__type_traits/conditional.h> #include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_unsigned.h> #include <__type_traits/void_t.h> #include <__utility/pair.h> #include <__utility/swap.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -58,6 +62,34 @@ struct __size_difference_type_traits<_Cp, __void_t +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz) { + static_assert(is_unsigned<_StorageType>::value, "__trailing_mask only works with unsigned types"); + return static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) { + static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types"); + return static_cast<_StorageType>( + static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz) & + std::__trailing_mask<_StorageType>(__clz)); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unsigned +__find_in_masked_range(_StoragePointer __word, unsigned __clz, unsigned __ctz) { + static_assert(is_unsigned::element_type>::value, + "__find_in_masked_range must be called with unsigned types"); + using _StorageType = typename pointer_traits<_StoragePointer>::element_type; + _LIBCPP_ASSERT_VALID_INPUT_RANGE( + __ctz + __clz < sizeof(_StorageType) * CHAR_BIT, "__find_in_masked_range called with invalid range"); + _StorageType __m = static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz) & + static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz); + _StorageType __b = std::__invert_if(*__word) & __m; + return static_cast(std::__countr_zero(__b)); +} + template ::value> class __bit_reference { using __storage_type _LIBCPP_NODEBUG = typename _Cp::__storage_type; diff --git a/libcxx/include/__fwd/bit_reference.h b/libcxx/include/__fwd/bit_reference.h index 6932effd95f30e..220366351ba752 100644 --- a/libcxx/include/__fwd/bit_reference.h +++ b/libcxx/include/__fwd/bit_reference.h @@ -10,8 +10,6 @@ #define _LIBCPP___FWD_BIT_REFERENCE_H #include <__config> -#include <__type_traits/enable_if.h> -#include <__type_traits/is_unsigned.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -25,9 +23,11 @@ class __bit_iterator; template struct __size_difference_type_traits; -template ::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _StorageType -__find_in_masked_range(_StorageType __word, unsigned __ctz, unsigned __clz, bool __find_val); +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz); + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz); _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp index 6940ff97a0ba5b..599b6355af565b 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -208,7 +208,7 @@ struct TestIntegerPromotions { } }; -TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { +TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { { using Alloc = sized_allocator; std::vector in(100, false, Alloc(1)); @@ -217,7 +217,7 @@ TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(199, false, Alloc(1)); in[in.size() - 2] = true; assert(std::find(in.begin(), in.end(), true) == in.end() - 2); } @@ -229,7 +229,7 @@ TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(257, false, Alloc(1)); in[in.size() - 2] = true; assert(std::find(in.begin(), in.end(), true) == in.end() - 2); } @@ -255,7 +255,7 @@ TEST_CONSTEXPR_CXX20 bool test() { #endif types::for_each(types::integral_types(), TestIntegerPromotions()); - test_bititer_with_custom_sized_types(); + test_bit_iterator_with_custom_sized_types(); return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index a2af568be37c04..d596e3a5c7970b 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -121,7 +121,7 @@ class TriviallyComparable { bool operator==(const TriviallyComparable&) const = default; }; -constexpr void test_bititer_with_custom_sized_types() { +constexpr void test_bit_iterator_with_custom_sized_types() { { using Alloc = sized_allocator; std::vector in(100, false, Alloc(1)); @@ -130,7 +130,7 @@ constexpr void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(199, false, Alloc(1)); in[in.size() - 2] = true; assert(std::ranges::find(in, true) == in.end() - 2); } @@ -142,7 +142,7 @@ constexpr void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(257, false, Alloc(1)); in[in.size() - 2] = true; assert(std::ranges::find(in, true) == in.end() - 2); } @@ -229,7 +229,7 @@ constexpr bool test() { } } - test_bititer_with_custom_sized_types(); + test_bit_iterator_with_custom_sized_types(); return true; } From libcxx-commits at lists.llvm.org Wed Feb 5 05:54:25 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Wed, 05 Feb 2025 05:54:25 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Reduce the dependency of the locale base API on the base system from the headers (PR #117764) In-Reply-To: Message-ID: <67a36d91.170a0220.2fdb5a.61fe@mx.google.com> https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/117764 >From 4a565124b0ba23c6ff6d34b1456be350cf999bef Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 26 Nov 2024 12:27:08 -0500 Subject: [PATCH 1/2] [libc++] Reduce the dependency of the locale base API on the base system from the headers Many parts of the locale base API are only required when building the shared/static library, but not from the headers. Document those functions and carve out a few of those that don't work when _XOPEN_SOURCE is defined to something old. Fixes #117630 --- libcxx/include/__locale_dir/locale_base_api.h | 17 +++++--- .../include/__locale_dir/support/bsd_like.h | 4 ++ libcxx/test/libcxx/xopen_source.gen.py | 42 +++++++++++++++++++ 3 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 libcxx/test/libcxx/xopen_source.gen.py diff --git a/libcxx/include/__locale_dir/locale_base_api.h b/libcxx/include/__locale_dir/locale_base_api.h index bbee9f49867fd9..e9d868148bb47f 100644 --- a/libcxx/include/__locale_dir/locale_base_api.h +++ b/libcxx/include/__locale_dir/locale_base_api.h @@ -23,12 +23,16 @@ // Variadic functions may be implemented as templates with a parameter pack instead // of C-style variadic functions. // +// Most of these functions are only required when building the library. Functions that are also +// required when merely using the headers are marked as such below. +// // TODO: __localeconv shouldn't take a reference, but the Windows implementation doesn't allow copying __locale_t +// TODO: Eliminate the need for any of these functions from the headers. // // Locale management // ----------------- // namespace __locale { -// using __locale_t = implementation-defined; +// using __locale_t = implementation-defined; // required by the headers // using __lconv_t = implementation-defined; // __locale_t __newlocale(int, const char*, __locale_t); // void __freelocale(__locale_t); @@ -60,8 +64,8 @@ // namespace __locale { // int __islower(int, __locale_t); // int __isupper(int, __locale_t); -// int __isdigit(int, __locale_t); -// int __isxdigit(int, __locale_t); +// int __isdigit(int, __locale_t); // required by the headers +// int __isxdigit(int, __locale_t); // required by the headers // int __toupper(int, __locale_t); // int __tolower(int, __locale_t); // int __strcoll(const char*, const char*, __locale_t); @@ -99,9 +103,10 @@ // int __mbtowc(wchar_t*, const char*, size_t, __locale_t); // size_t __mbrlen(const char*, size_t, mbstate_t*, __locale_t); // size_t __mbsrtowcs(wchar_t*, const char**, size_t, mbstate_t*, __locale_t); -// int __snprintf(char*, size_t, __locale_t, const char*, ...); -// int __asprintf(char**, __locale_t, const char*, ...); -// int __sscanf(const char*, __locale_t, const char*, ...); +// +// int __snprintf(char*, size_t, __locale_t, const char*, ...); // required by the headers +// int __asprintf(char**, __locale_t, const char*, ...); // required by the headers +// int __sscanf(const char*, __locale_t, const char*, ...); // required by the headers // } #if defined(__APPLE__) diff --git a/libcxx/include/__locale_dir/support/bsd_like.h b/libcxx/include/__locale_dir/support/bsd_like.h index c0080b13a08cf3..61d5bb45d05f11 100644 --- a/libcxx/include/__locale_dir/support/bsd_like.h +++ b/libcxx/include/__locale_dir/support/bsd_like.h @@ -160,19 +160,23 @@ inline _LIBCPP_HIDE_FROM_ABI wint_t __btowc(int __c, __locale_t __loc) { return inline _LIBCPP_HIDE_FROM_ABI int __wctob(wint_t __c, __locale_t __loc) { return ::wctob_l(__c, __loc); } +# ifdef _LIBCPP_BUILDING_LIBRARY inline _LIBCPP_HIDE_FROM_ABI size_t __wcsnrtombs(char* __dest, const wchar_t** __src, size_t __nwc, size_t __len, mbstate_t* __ps, __locale_t __loc) { return ::wcsnrtombs_l(__dest, __src, __nwc, __len, __ps, __loc); } +# endif inline _LIBCPP_HIDE_FROM_ABI size_t __wcrtomb(char* __s, wchar_t __wc, mbstate_t* __ps, __locale_t __loc) { return ::wcrtomb_l(__s, __wc, __ps, __loc); } +# ifdef _LIBCPP_BUILDING_LIBRARY inline _LIBCPP_HIDE_FROM_ABI size_t __mbsnrtowcs(wchar_t* __dest, const char** __src, size_t __nms, size_t __len, mbstate_t* __ps, __locale_t __loc) { return ::mbsnrtowcs_l(__dest, __src, __nms, __len, __ps, __loc); } +# endif inline _LIBCPP_HIDE_FROM_ABI size_t __mbrtowc(wchar_t* __pwc, const char* __s, size_t __n, mbstate_t* __ps, __locale_t __loc) { diff --git a/libcxx/test/libcxx/xopen_source.gen.py b/libcxx/test/libcxx/xopen_source.gen.py new file mode 100644 index 00000000000000..39b8bd0e8ecef4 --- /dev/null +++ b/libcxx/test/libcxx/xopen_source.gen.py @@ -0,0 +1,42 @@ +# ===----------------------------------------------------------------------===## +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ===----------------------------------------------------------------------===## + +# Make sure that libc++ headers work when defining _XOPEN_SOURCE=500. +# We may not want to guarantee this forever, but since this works today and +# it's something that users rely on, it makes sense to put a test on it. +# +# https://github.com/llvm/llvm-project/issues/117630 + +# RUN: %{python} %s %{libcxx-dir}/utils + +import sys + +sys.path.append(sys.argv[1]) +from libcxx.header_information import ( + lit_header_restrictions, + lit_header_undeprecations, + public_headers, +) + +for header in public_headers: + for version in (500, 600, 700): + # TODO: currently uses ::fseeko unguarded, which fails with _XOPEN_SOURCE=500. + if header == "fstream" and version == 500: + continue + + print( + f"""\ +//--- {header}.xopen_source_{version}.compile.pass.cpp +{lit_header_restrictions.get(header, '')} +{lit_header_undeprecations.get(header, '')} + +// ADDITIONAL_COMPILE_FLAGS: -D_XOPEN_SOURCE={version} + +#include <{header}> +""" + ) >From f7e6a7ab7e5ea08e324cc94d4f471eb25c222869 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 5 Feb 2025 08:54:13 -0500 Subject: [PATCH 2/2] Guard more functions --- libcxx/include/__locale_dir/locale_base_api.h | 39 ++++++++++++------- .../include/__locale_dir/support/bsd_like.h | 20 +++++----- libcxx/include/__locale_dir/support/fuchsia.h | 9 +++-- .../support/no_locale/characters.h | 8 +++- libcxx/include/__locale_dir/support/windows.h | 18 ++++++--- libcxx/test/libcxx/xopen_source.gen.py | 7 ++++ 6 files changed, 68 insertions(+), 33 deletions(-) diff --git a/libcxx/include/__locale_dir/locale_base_api.h b/libcxx/include/__locale_dir/locale_base_api.h index e9d868148bb47f..c1e73caeecced9 100644 --- a/libcxx/include/__locale_dir/locale_base_api.h +++ b/libcxx/include/__locale_dir/locale_base_api.h @@ -40,6 +40,7 @@ // __lconv_t* __localeconv(__locale_t&); // } // +// // required by the headers // #define _LIBCPP_COLLATE_MASK /* implementation-defined */ // #define _LIBCPP_CTYPE_MASK /* implementation-defined */ // #define _LIBCPP_MONETARY_MASK /* implementation-defined */ @@ -52,6 +53,7 @@ // Strtonum functions // ------------------ // namespace __locale { +// // required by the headers // float __strtof(const char*, char**, __locale_t); // double __strtod(const char*, char**, __locale_t); // long double __strtold(const char*, char**, __locale_t); @@ -148,8 +150,19 @@ namespace __locale { // // Locale management // +# define _LIBCPP_COLLATE_MASK LC_COLLATE_MASK +# define _LIBCPP_CTYPE_MASK LC_CTYPE_MASK +# define _LIBCPP_MONETARY_MASK LC_MONETARY_MASK +# define _LIBCPP_NUMERIC_MASK LC_NUMERIC_MASK +# define _LIBCPP_TIME_MASK LC_TIME_MASK +# define _LIBCPP_MESSAGES_MASK LC_MESSAGES_MASK +# define _LIBCPP_ALL_MASK LC_ALL_MASK +# define _LIBCPP_LC_ALL LC_ALL + using __locale_t _LIBCPP_NODEBUG = locale_t; -using __lconv_t _LIBCPP_NODEBUG = lconv; + +# if defined(_LIBCPP_BUILDING_LIBRARY) +using __lconv_t _LIBCPP_NODEBUG = lconv; inline _LIBCPP_HIDE_FROM_ABI __locale_t __newlocale(int __category_mask, const char* __name, __locale_t __loc) { return newlocale(__category_mask, __name, __loc); @@ -162,15 +175,7 @@ inline _LIBCPP_HIDE_FROM_ABI char* __setlocale(int __category, char const* __loc inline _LIBCPP_HIDE_FROM_ABI void __freelocale(__locale_t __loc) { freelocale(__loc); } inline _LIBCPP_HIDE_FROM_ABI __lconv_t* __localeconv(__locale_t& __loc) { return __libcpp_localeconv_l(__loc); } - -# define _LIBCPP_COLLATE_MASK LC_COLLATE_MASK -# define _LIBCPP_CTYPE_MASK LC_CTYPE_MASK -# define _LIBCPP_MONETARY_MASK LC_MONETARY_MASK -# define _LIBCPP_NUMERIC_MASK LC_NUMERIC_MASK -# define _LIBCPP_TIME_MASK LC_TIME_MASK -# define _LIBCPP_MESSAGES_MASK LC_MESSAGES_MASK -# define _LIBCPP_ALL_MASK LC_ALL_MASK -# define _LIBCPP_LC_ALL LC_ALL +# endif // _LIBCPP_BUILDING_LIBRARY // // Strtonum functions @@ -199,10 +204,15 @@ __strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) { // // Character manipulation functions // +# if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __islower(int __ch, __locale_t __loc) { return islower_l(__ch, __loc); } inline _LIBCPP_HIDE_FROM_ABI int __isupper(int __ch, __locale_t __loc) { return isupper_l(__ch, __loc); } +# endif + inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __ch, __locale_t __loc) { return isdigit_l(__ch, __loc); } inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __ch, __locale_t __loc) { return isxdigit_l(__ch, __loc); } + +# if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __strcoll(const char* __s1, const char* __s2, __locale_t __loc) { return strcoll_l(__s1, __s2, __loc); } @@ -212,7 +222,7 @@ inline _LIBCPP_HIDE_FROM_ABI size_t __strxfrm(char* __dest, const char* __src, s inline _LIBCPP_HIDE_FROM_ABI int __toupper(int __ch, __locale_t __loc) { return toupper_l(__ch, __loc); } inline _LIBCPP_HIDE_FROM_ABI int __tolower(int __ch, __locale_t __loc) { return tolower_l(__ch, __loc); } -# if _LIBCPP_HAS_WIDE_CHARACTERS +# if _LIBCPP_HAS_WIDE_CHARACTERS inline _LIBCPP_HIDE_FROM_ABI int __wcscoll(const wchar_t* __s1, const wchar_t* __s2, __locale_t __loc) { return wcscoll_l(__s1, __s2, __loc); } @@ -234,7 +244,7 @@ inline _LIBCPP_HIDE_FROM_ABI int __iswpunct(wint_t __ch, __locale_t __loc) { ret inline _LIBCPP_HIDE_FROM_ABI int __iswxdigit(wint_t __ch, __locale_t __loc) { return iswxdigit_l(__ch, __loc); } inline _LIBCPP_HIDE_FROM_ABI wint_t __towupper(wint_t __ch, __locale_t __loc) { return towupper_l(__ch, __loc); } inline _LIBCPP_HIDE_FROM_ABI wint_t __towlower(wint_t __ch, __locale_t __loc) { return towlower_l(__ch, __loc); } -# endif +# endif inline _LIBCPP_HIDE_FROM_ABI size_t __strftime(char* __s, size_t __max, const char* __format, const tm* __tm, __locale_t __loc) { @@ -247,7 +257,7 @@ __strftime(char* __s, size_t __max, const char* __format, const tm* __tm, __loca inline _LIBCPP_HIDE_FROM_ABI decltype(__libcpp_mb_cur_max_l(__locale_t())) __mb_len_max(__locale_t __loc) { return __libcpp_mb_cur_max_l(__loc); } -# if _LIBCPP_HAS_WIDE_CHARACTERS +# if _LIBCPP_HAS_WIDE_CHARACTERS inline _LIBCPP_HIDE_FROM_ABI wint_t __btowc(int __ch, __locale_t __loc) { return __libcpp_btowc_l(__ch, __loc); } inline _LIBCPP_HIDE_FROM_ABI int __wctob(wint_t __ch, __locale_t __loc) { return __libcpp_wctob_l(__ch, __loc); } inline _LIBCPP_HIDE_FROM_ABI size_t @@ -275,7 +285,8 @@ inline _LIBCPP_HIDE_FROM_ABI size_t __mbsrtowcs(wchar_t* __dest, const char** __src, size_t __len, mbstate_t* __ps, __locale_t __loc) { return __libcpp_mbsrtowcs_l(__dest, __src, __len, __ps, __loc); } -# endif +# endif // _LIBCPP_HAS_WIDE_CHARACTERS +# endif // _LIBCPP_BUILDING_LIBRARY _LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wgcc-compat") diff --git a/libcxx/include/__locale_dir/support/bsd_like.h b/libcxx/include/__locale_dir/support/bsd_like.h index 61d5bb45d05f11..26274b4b4a45a3 100644 --- a/libcxx/include/__locale_dir/support/bsd_like.h +++ b/libcxx/include/__locale_dir/support/bsd_like.h @@ -46,7 +46,8 @@ namespace __locale { #define _LIBCPP_LC_ALL LC_ALL using __locale_t = ::locale_t; -using __lconv_t = std::lconv; +#if defined(_LIBCPP_BUILDING_LIBRARY) +using __lconv_t = std::lconv; inline _LIBCPP_HIDE_FROM_ABI __locale_t __newlocale(int __category_mask, const char* __locale, __locale_t __base) { return ::newlocale(__category_mask, __locale, __base); @@ -59,6 +60,7 @@ inline _LIBCPP_HIDE_FROM_ABI char* __setlocale(int __category, char const* __loc } inline _LIBCPP_HIDE_FROM_ABI __lconv_t* __localeconv(__locale_t& __loc) { return ::localeconv_l(__loc); } +#endif // _LIBCPP_BUILDING_LIBRARY // // Strtonum functions @@ -87,14 +89,17 @@ __strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) { // // Character manipulation functions // +#if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __islower(int __c, __locale_t __loc) { return ::islower_l(__c, __loc); } inline _LIBCPP_HIDE_FROM_ABI int __isupper(int __c, __locale_t __loc) { return ::isupper_l(__c, __loc); } +#endif inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t __loc) { return ::isdigit_l(__c, __loc); } inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t __loc) { return ::isxdigit_l(__c, __loc); } +#if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __toupper(int __c, __locale_t __loc) { return ::toupper_l(__c, __loc); } inline _LIBCPP_HIDE_FROM_ABI int __tolower(int __c, __locale_t __loc) { return ::tolower_l(__c, __loc); } @@ -107,7 +112,7 @@ inline _LIBCPP_HIDE_FROM_ABI size_t __strxfrm(char* __dest, const char* __src, s return ::strxfrm_l(__dest, __src, __n, __loc); } -#if _LIBCPP_HAS_WIDE_CHARACTERS +# if _LIBCPP_HAS_WIDE_CHARACTERS inline _LIBCPP_HIDE_FROM_ABI int __iswctype(wint_t __c, wctype_t __type, __locale_t __loc) { return ::iswctype_l(__c, __type, __loc); } @@ -143,7 +148,7 @@ inline _LIBCPP_HIDE_FROM_ABI int __wcscoll(const wchar_t* __ws1, const wchar_t* inline _LIBCPP_HIDE_FROM_ABI size_t __wcsxfrm(wchar_t* __dest, const wchar_t* __src, size_t __n, __locale_t __loc) { return ::wcsxfrm_l(__dest, __src, __n, __loc); } -#endif // _LIBCPP_HAS_WIDE_CHARACTERS +# endif // _LIBCPP_HAS_WIDE_CHARACTERS inline _LIBCPP_HIDE_FROM_ABI size_t __strftime(char* __s, size_t __max, const char* __format, const struct tm* __tm, __locale_t __loc) { @@ -155,28 +160,24 @@ __strftime(char* __s, size_t __max, const char* __format, const struct tm* __tm, // inline _LIBCPP_HIDE_FROM_ABI decltype(MB_CUR_MAX) __mb_len_max(__locale_t __loc) { return MB_CUR_MAX_L(__loc); } -#if _LIBCPP_HAS_WIDE_CHARACTERS +# if _LIBCPP_HAS_WIDE_CHARACTERS inline _LIBCPP_HIDE_FROM_ABI wint_t __btowc(int __c, __locale_t __loc) { return ::btowc_l(__c, __loc); } inline _LIBCPP_HIDE_FROM_ABI int __wctob(wint_t __c, __locale_t __loc) { return ::wctob_l(__c, __loc); } -# ifdef _LIBCPP_BUILDING_LIBRARY inline _LIBCPP_HIDE_FROM_ABI size_t __wcsnrtombs(char* __dest, const wchar_t** __src, size_t __nwc, size_t __len, mbstate_t* __ps, __locale_t __loc) { return ::wcsnrtombs_l(__dest, __src, __nwc, __len, __ps, __loc); } -# endif inline _LIBCPP_HIDE_FROM_ABI size_t __wcrtomb(char* __s, wchar_t __wc, mbstate_t* __ps, __locale_t __loc) { return ::wcrtomb_l(__s, __wc, __ps, __loc); } -# ifdef _LIBCPP_BUILDING_LIBRARY inline _LIBCPP_HIDE_FROM_ABI size_t __mbsnrtowcs(wchar_t* __dest, const char** __src, size_t __nms, size_t __len, mbstate_t* __ps, __locale_t __loc) { return ::mbsnrtowcs_l(__dest, __src, __nms, __len, __ps, __loc); } -# endif inline _LIBCPP_HIDE_FROM_ABI size_t __mbrtowc(wchar_t* __pwc, const char* __s, size_t __n, mbstate_t* __ps, __locale_t __loc) { @@ -195,7 +196,8 @@ inline _LIBCPP_HIDE_FROM_ABI size_t __mbsrtowcs(wchar_t* __dest, const char** __src, size_t __len, mbstate_t* __ps, __locale_t __loc) { return ::mbsrtowcs_l(__dest, __src, __len, __ps, __loc); } -#endif +# endif // _LIBCPP_HAS_WIDE_CHARACTERS +#endif // _LIBCPP_BUILDING_LIBRARY _LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wgcc-compat") diff --git a/libcxx/include/__locale_dir/support/fuchsia.h b/libcxx/include/__locale_dir/support/fuchsia.h index 237f48562d6e02..fb9de74ab7c7bf 100644 --- a/libcxx/include/__locale_dir/support/fuchsia.h +++ b/libcxx/include/__locale_dir/support/fuchsia.h @@ -50,7 +50,9 @@ struct __locale_guard { #define _LIBCPP_LC_ALL LC_ALL using __locale_t = locale_t; -using __lconv_t = std::lconv; + +#if defined(_LIBCPP_BUILDING_LIBRARY) +using __lconv_t = std::lconv; inline _LIBCPP_HIDE_FROM_ABI __locale_t __newlocale(int __category_mask, const char* __name, __locale_t __loc) { return ::newlocale(__category_mask, __name, __loc); @@ -74,7 +76,7 @@ inline _LIBCPP_HIDE_FROM_ABI decltype(MB_CUR_MAX) __mb_len_max(__locale_t __loc) __locale_guard __current(__loc); return MB_CUR_MAX; } -#if _LIBCPP_HAS_WIDE_CHARACTERS +# if _LIBCPP_HAS_WIDE_CHARACTERS inline _LIBCPP_HIDE_FROM_ABI wint_t __btowc(int __ch, __locale_t __loc) { __locale_guard __current(__loc); return std::btowc(__ch); @@ -115,7 +117,8 @@ __mbsrtowcs(wchar_t* __dest, const char** __src, size_t __len, mbstate_t* __ps, __locale_guard __current(__loc); return ::mbsrtowcs(__dest, __src, __len, __ps); } -#endif +# endif // _LIBCPP_HAS_WIDE_CHARACTERS +#endif // _LIBCPP_BUILDING_LIBRARY _LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wgcc-compat") diff --git a/libcxx/include/__locale_dir/support/no_locale/characters.h b/libcxx/include/__locale_dir/support/no_locale/characters.h index 20e45fc350e2ef..4fb48ed9ceac19 100644 --- a/libcxx/include/__locale_dir/support/no_locale/characters.h +++ b/libcxx/include/__locale_dir/support/no_locale/characters.h @@ -29,14 +29,17 @@ namespace __locale { // // Character manipulation functions // +#if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __islower(int __c, __locale_t) { return std::islower(__c); } inline _LIBCPP_HIDE_FROM_ABI int __isupper(int __c, __locale_t) { return std::isupper(__c); } +#endif inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t) { return std::isdigit(__c); } inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t) { return std::isxdigit(__c); } +#if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __toupper(int __c, __locale_t) { return std::toupper(__c); } inline _LIBCPP_HIDE_FROM_ABI int __tolower(int __c, __locale_t) { return std::tolower(__c); } @@ -49,7 +52,7 @@ inline _LIBCPP_HIDE_FROM_ABI size_t __strxfrm(char* __dest, const char* __src, s return std::strxfrm(__dest, __src, __n); } -#if _LIBCPP_HAS_WIDE_CHARACTERS +# if _LIBCPP_HAS_WIDE_CHARACTERS inline _LIBCPP_HIDE_FROM_ABI int __iswctype(wint_t __c, wctype_t __type, __locale_t) { return std::iswctype(__c, __type); } @@ -85,12 +88,13 @@ inline _LIBCPP_HIDE_FROM_ABI int __wcscoll(const wchar_t* __ws1, const wchar_t* inline _LIBCPP_HIDE_FROM_ABI size_t __wcsxfrm(wchar_t* __dest, const wchar_t* __src, size_t __n, __locale_t) { return std::wcsxfrm(__dest, __src, __n); } -#endif // _LIBCPP_HAS_WIDE_CHARACTERS +# endif // _LIBCPP_HAS_WIDE_CHARACTERS inline _LIBCPP_HIDE_FROM_ABI size_t __strftime(char* __s, size_t __max, const char* __format, const struct tm* __tm, __locale_t) { return std::strftime(__s, __max, __format, __tm); } +#endif // _LIBCPP_BUILDING_LIBRARY } // namespace __locale _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__locale_dir/support/windows.h b/libcxx/include/__locale_dir/support/windows.h index f0f76c527264a5..56d34c6f0e6cac 100644 --- a/libcxx/include/__locale_dir/support/windows.h +++ b/libcxx/include/__locale_dir/support/windows.h @@ -153,6 +153,7 @@ class __locale_t { __lconv_storage* __lc_ = nullptr; }; +#if defined(_LIBCPP_BUILDING_LIBRARY) _LIBCPP_EXPORTED_FROM_ABI __locale_t __newlocale(int __mask, const char* __locale, __locale_t __base); inline _LIBCPP_HIDE_FROM_ABI void __freelocale(__locale_t __loc) { ::_free_locale(__loc); } inline _LIBCPP_HIDE_FROM_ABI char* __setlocale(int __category, const char* __locale) { @@ -162,6 +163,7 @@ inline _LIBCPP_HIDE_FROM_ABI char* __setlocale(int __category, const char* __loc return __new_locale; } _LIBCPP_EXPORTED_FROM_ABI __lconv_t* __localeconv(__locale_t& __loc); +#endif // _LIBCPP_BUILDING_LIBRARY // // Strtonum functions @@ -195,14 +197,17 @@ __strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) { // // Character manipulation functions // +#if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __islower(int __c, __locale_t __loc) { return _islower_l(__c, __loc); } inline _LIBCPP_HIDE_FROM_ABI int __isupper(int __c, __locale_t __loc) { return _isupper_l(__c, __loc); } +#endif inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t __loc) { return _isdigit_l(__c, __loc); } inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t __loc) { return _isxdigit_l(__c, __loc); } +#if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __toupper(int __c, __locale_t __loc) { return ::_toupper_l(__c, __loc); } inline _LIBCPP_HIDE_FROM_ABI int __tolower(int __c, __locale_t __loc) { return ::_tolower_l(__c, __loc); } @@ -215,7 +220,7 @@ inline _LIBCPP_HIDE_FROM_ABI size_t __strxfrm(char* __dest, const char* __src, s return ::_strxfrm_l(__dest, __src, __n, __loc); } -#if _LIBCPP_HAS_WIDE_CHARACTERS +# if _LIBCPP_HAS_WIDE_CHARACTERS inline _LIBCPP_HIDE_FROM_ABI int __iswctype(wint_t __c, wctype_t __type, __locale_t __loc) { return ::_iswctype_l(__c, __type, __loc); } @@ -240,16 +245,16 @@ inline _LIBCPP_HIDE_FROM_ABI int __wcscoll(const wchar_t* __ws1, const wchar_t* inline _LIBCPP_HIDE_FROM_ABI size_t __wcsxfrm(wchar_t* __dest, const wchar_t* __src, size_t __n, __locale_t __loc) { return ::_wcsxfrm_l(__dest, __src, __n, __loc); } -#endif // _LIBCPP_HAS_WIDE_CHARACTERS +# endif // _LIBCPP_HAS_WIDE_CHARACTERS -#if defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0800 +# if defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0800 _LIBCPP_EXPORTED_FROM_ABI size_t __strftime(char*, size_t, const char*, const struct tm*, __locale_t); -#else +# else inline _LIBCPP_HIDE_FROM_ABI size_t __strftime(char* __ret, size_t __n, const char* __format, const struct tm* __tm, __locale_t __loc) { return ::_strftime_l(__ret, __n, __format, __tm, __loc); } -#endif +# endif // // Other functions @@ -273,6 +278,7 @@ _LIBCPP_EXPORTED_FROM_ABI size_t __mbrlen(const char* __restrict, size_t, mbstat _LIBCPP_EXPORTED_FROM_ABI size_t __mbsrtowcs(wchar_t* __restrict, const char** __restrict, size_t, mbstate_t* __restrict, __locale_t); +#endif // _LIBCPP_BUILDING_LIBRARY _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 4, 5) int __snprintf( char* __ret, size_t __n, __locale_t __loc, const char* __format, ...); @@ -297,6 +303,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __s _LIBCPP_DIAGNOSTIC_POP #undef _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT +#if defined(_LIBCPP_BUILDING_LIBRARY) struct __locale_guard { _LIBCPP_HIDE_FROM_ABI __locale_guard(__locale_t __l) : __status(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)) { // Setting the locale can be expensive even when the locale given is @@ -328,6 +335,7 @@ struct __locale_guard { int __status; char* __locale_all = nullptr; }; +#endif // _LIBCPP_BUILDING_LIBRARY } // namespace __locale _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/libcxx/xopen_source.gen.py b/libcxx/test/libcxx/xopen_source.gen.py index 39b8bd0e8ecef4..15666805dc66ff 100644 --- a/libcxx/test/libcxx/xopen_source.gen.py +++ b/libcxx/test/libcxx/xopen_source.gen.py @@ -13,6 +13,7 @@ # https://github.com/llvm/llvm-project/issues/117630 # RUN: %{python} %s %{libcxx-dir}/utils +# END. import sys @@ -32,6 +33,12 @@ print( f"""\ //--- {header}.xopen_source_{version}.compile.pass.cpp + +// Some parts of the code like use non-standard functions in their implementation, +// and these functions are not provided when _XOPEN_SOURCE is set to older values. This +// breaks when building with modules even when we don't use the offending headers directly. +// UNSUPPORTED: clang-modules-build + {lit_header_restrictions.get(header, '')} {lit_header_undeprecations.get(header, '')} From libcxx-commits at lists.llvm.org Wed Feb 5 05:56:16 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Wed, 05 Feb 2025 05:56:16 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Replace __is_trivially_relocatable by is_trivially_copyable (PR #124970) In-Reply-To: Message-ID: <67a36e00.050a0220.f59df.b459@mx.google.com> https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/124970 >From 6da2fc4d827722f0adc5e445232d62fb191d3a61 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 29 Jan 2025 13:18:11 -0500 Subject: [PATCH 1/5] [libc++] Replace __is_trivially_relocatable by is_trivially_copyable The __is_trivially_relocatable builtin has semantics that do not correspond to any current or future notion of trivial relocation. Furthermore, it currently leads to incorrect optimizations for some types on supported compilers: - Clang on Windows where types with non-trivial destructors get incorrectly optimized - AppleClang where types with non-trivial move constructors get incorrectly optimized Until there is an agreed upon and bugfree implementation of what it means to be trivially relocatable, it is safer to simply use trivially copyable instead. This doesn't leave a lot of types behind and is definitely correct. --- .../__type_traits/is_trivially_relocatable.h | 7 -- .../is_trivially_relocatable.compile.pass.cpp | 10 +++ .../vector/trivial_relocation.pass.cpp | 67 +++++++++++++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp diff --git a/libcxx/include/__type_traits/is_trivially_relocatable.h b/libcxx/include/__type_traits/is_trivially_relocatable.h index c0871731cc0016b..ecc97a41dfbdcbd 100644 --- a/libcxx/include/__type_traits/is_trivially_relocatable.h +++ b/libcxx/include/__type_traits/is_trivially_relocatable.h @@ -11,7 +11,6 @@ #include <__config> #include <__type_traits/enable_if.h> -#include <__type_traits/integral_constant.h> #include <__type_traits/is_same.h> #include <__type_traits/is_trivially_copyable.h> @@ -23,14 +22,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD // A type is trivially relocatable if a move construct + destroy of the original object is equivalent to // `memcpy(dst, src, sizeof(T))`. - -#if __has_builtin(__is_trivially_relocatable) -template -struct __libcpp_is_trivially_relocatable : integral_constant {}; -#else template struct __libcpp_is_trivially_relocatable : is_trivially_copyable<_Tp> {}; -#endif template struct __libcpp_is_trivially_relocatable<_Tp, diff --git a/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp index 674df1d0219057d..e43f38aa26f7d0a 100644 --- a/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp +++ b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp @@ -60,6 +60,16 @@ static_assert(std::__libcpp_is_trivially_relocatable: static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); #endif +struct NonTrivialMoveConstructor { + NonTrivialMoveConstructor(NonTrivialMoveConstructor&&); +}; +static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + +struct NonTrivialDestructor { + ~NonTrivialDestructor() {} +}; +static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + // library-internal types // ---------------------- diff --git a/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp b/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp new file mode 100644 index 000000000000000..e109a5034032ddb --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// Make sure we don't miscompile vector operations for types that shouldn't be considered +// trivially relocatable. + +#include +#include +#include + +#include "test_macros.h" + +struct Tracker { + std::size_t move_constructs = 0; +}; + +struct [[clang::trivial_abi]] Inner { + TEST_CONSTEXPR explicit Inner(Tracker* tracker) : tracker_(tracker) {} + TEST_CONSTEXPR Inner(const Inner& rhs) : tracker_(rhs.tracker_) { tracker_->move_constructs += 1; } + TEST_CONSTEXPR Inner(Inner&& rhs) : tracker_(rhs.tracker_) { tracker_->move_constructs += 1; } + Tracker* tracker_; +}; + +// Even though this type contains a trivial_abi type, it is not trivially move-constructible, +// so we should not attempt to optimize its move construction + destroy using trivial relocation. +struct NotTriviallyMovable { + TEST_CONSTEXPR explicit NotTriviallyMovable(Tracker* tracker) : inner_(tracker) {} + TEST_CONSTEXPR NotTriviallyMovable(NotTriviallyMovable&& other) : inner_(std::move(other.inner_)) {} + Inner inner_; +}; +static_assert(!std::is_trivially_copyable::value, ""); +LIBCPP_STATIC_ASSERT(!std::__libcpp_is_trivially_relocatable::value, ""); + +TEST_CONSTEXPR_CXX20 bool tests() { + Tracker track; + std::vector v; + + // Fill the vector at its capacity, such that any subsequent push_back would require growing. + v.reserve(5); + for (std::size_t i = 0; i != 5; ++i) { + v.emplace_back(&track); + } + assert(track.move_constructs == 0); + assert(v.size() == 5); + + // Force a reallocation of the buffer + relocalization of the elements. + // All the existing elements of the vector should be move-constructed to their new location. + v.emplace_back(&track); + assert(track.move_constructs == 5); + + return true; +} + +int main(int, char**) { + tests(); +#if TEST_STD_VER >= 20 + static_assert(tests()); +#endif + return 0; +} >From 798bb8067126208fc665d23a0d1b46f5820c9e59 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 4 Feb 2025 14:41:28 -0500 Subject: [PATCH 2/5] Use && 0 and add a comment --- libcxx/include/__type_traits/is_trivially_relocatable.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libcxx/include/__type_traits/is_trivially_relocatable.h b/libcxx/include/__type_traits/is_trivially_relocatable.h index ecc97a41dfbdcbd..9b0e240de55f4ec 100644 --- a/libcxx/include/__type_traits/is_trivially_relocatable.h +++ b/libcxx/include/__type_traits/is_trivially_relocatable.h @@ -22,8 +22,17 @@ _LIBCPP_BEGIN_NAMESPACE_STD // A type is trivially relocatable if a move construct + destroy of the original object is equivalent to // `memcpy(dst, src, sizeof(T))`. +// +// Note that we don't use the __is_trivially_relocatable Clang builtin right now because it does not +// implement the semantics of any current or future trivial relocation proposal and it can lead to +// incorrect optimizations on some platforms (Windows) and supported compilers (AppleClang). +#if __has_builtin(__is_trivially_relocatable) && 0 +template +struct __libcpp_is_trivially_relocatable : integral_constant {}; +#else template struct __libcpp_is_trivially_relocatable : is_trivially_copyable<_Tp> {}; +#endif template struct __libcpp_is_trivially_relocatable<_Tp, >From 55eaf470a98736e6ac2cfa7eb68d3a812bb0d233 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 4 Feb 2025 14:45:04 -0500 Subject: [PATCH 3/5] Make test portable --- .../sequences/vector/trivial_relocation.pass.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp b/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp index e109a5034032ddb..d093ae8b8771656 100644 --- a/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp @@ -44,16 +44,18 @@ TEST_CONSTEXPR_CXX20 bool tests() { // Fill the vector at its capacity, such that any subsequent push_back would require growing. v.reserve(5); - for (std::size_t i = 0; i != 5; ++i) { + std::size_t const capacity = v.capacity(); // could technically be more than 5 + while (v.size() < v.capacity()) { v.emplace_back(&track); } assert(track.move_constructs == 0); - assert(v.size() == 5); + assert(v.capacity() == capacity); + assert(v.size() == capacity); // Force a reallocation of the buffer + relocalization of the elements. // All the existing elements of the vector should be move-constructed to their new location. v.emplace_back(&track); - assert(track.move_constructs == 5); + assert(track.move_constructs == capacity); return true; } >From dd56c13bc292c971b310e70e928bfa84db40c246 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 4 Feb 2025 14:59:02 -0500 Subject: [PATCH 4/5] Missing include --- .../std/containers/sequences/vector/trivial_relocation.pass.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp b/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp index d093ae8b8771656..3d775d3604630e5 100644 --- a/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/trivial_relocation.pass.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "test_macros.h" >From f846c2afabe7cf3d3da286a35c946238cbfa906f Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 5 Feb 2025 08:56:03 -0500 Subject: [PATCH 5/5] Poke CI From libcxx-commits at lists.llvm.org Wed Feb 5 05:57:20 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Wed, 05 Feb 2025 05:57:20 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Also provide an alignment assumption for vector in C++03 mode (PR #124839) In-Reply-To: Message-ID: <67a36e40.630a0220.3aada3.7cc7@mx.google.com> https://github.com/ldionne milestoned https://github.com/llvm/llvm-project/pull/124839 From libcxx-commits at lists.llvm.org Wed Feb 5 05:57:26 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Wed, 05 Feb 2025 05:57:26 -0800 (PST) Subject: [libcxx-commits] [libcxx] ccb08b9 - [libc++] Also provide an alignment assumption for vector in C++03 mode (#124839) Message-ID: <67a36e46.a70a0220.33abff.8863@mx.google.com> Author: Louis Dionne Date: 2025-02-05T08:57:22-05:00 New Revision: ccb08b9dab7d829f8d9703d8b46b98e2d6717d0e URL: https://github.com/llvm/llvm-project/commit/ccb08b9dab7d829f8d9703d8b46b98e2d6717d0e DIFF: https://github.com/llvm/llvm-project/commit/ccb08b9dab7d829f8d9703d8b46b98e2d6717d0e.diff LOG: [libc++] Also provide an alignment assumption for vector in C++03 mode (#124839) There's no reason not to, and it's easy enough to do using enable_if. As a drive-by change, also add a missing _LIBCPP_NO_CFI attribute on __add_alignment_assumption. Added: Modified: libcxx/include/__vector/vector.h Removed: ################################################################################ diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h index 66cb622e2096330..bad676a56a8e643 100644 --- a/libcxx/include/__vector/vector.h +++ b/libcxx/include/__vector/vector.h @@ -783,14 +783,18 @@ class _LIBCPP_TEMPLATE_VIS vector { _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(vector&, false_type) _NOEXCEPT {} - static _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __add_alignment_assumption(pointer __p) _NOEXCEPT { -#ifndef _LIBCPP_CXX03_LANG - if constexpr (is_pointer::value) { - if (!__libcpp_is_constant_evaluated()) { - return static_cast(__builtin_assume_aligned(__p, alignof(decltype(*__p)))); - } + template ::value, int> = 0> + static _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI pointer + __add_alignment_assumption(_Ptr __p) _NOEXCEPT { + if (!__libcpp_is_constant_evaluated()) { + return static_cast(__builtin_assume_aligned(__p, _LIBCPP_ALIGNOF(decltype(*__p)))); } -#endif + return __p; + } + + template ::value, int> = 0> + static _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI pointer + __add_alignment_assumption(_Ptr __p) _NOEXCEPT { return __p; } }; From libcxx-commits at lists.llvm.org Wed Feb 5 05:57:29 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Wed, 05 Feb 2025 05:57:29 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Also provide an alignment assumption for vector in C++03 mode (PR #124839) In-Reply-To: Message-ID: <67a36e49.170a0220.f7149.7c44@mx.google.com> https://github.com/ldionne closed https://github.com/llvm/llvm-project/pull/124839 From libcxx-commits at lists.llvm.org Wed Feb 5 05:58:29 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Wed, 05 Feb 2025 05:58:29 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Also provide an alignment assumption for vector in C++03 mode (PR #124839) In-Reply-To: Message-ID: <67a36e85.a70a0220.3b000f.c7e8@mx.google.com> ldionne wrote: /cherry-pick ccb08b9 https://github.com/llvm/llvm-project/pull/124839 From libcxx-commits at lists.llvm.org Wed Feb 5 06:06:33 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Wed, 05 Feb 2025 06:06:33 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Also provide an alignment assumption for vector in C++03 mode (PR #124839) In-Reply-To: Message-ID: <67a37069.a70a0220.3d34f5.8798@mx.google.com> llvmbot wrote: /pull-request llvm/llvm-project#125860 https://github.com/llvm/llvm-project/pull/124839 From libcxx-commits at lists.llvm.org Wed Feb 5 06:18:24 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Wed, 05 Feb 2025 06:18:24 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a37330.050a0220.2389d.aa16@mx.google.com> https://github.com/ldionne closed https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Wed Feb 5 06:18:24 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Wed, 05 Feb 2025 06:18:24 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Provide sized deallocation declarations even when the compiler doesn't support sized deallocation (PR #125577) In-Reply-To: Message-ID: <67a37330.630a0220.3aada3.8cfc@mx.google.com> ldionne wrote: > I don't think that's the problem. The sized overload just calls the unsized one by default, so I don't see how that's breaking. My understanding is that the fundamental is that the compiler silently changes to generating calls to functions which may not exist in the runtime yet. That could probably have been solved by using availability information, but most platforms don't have that. I think you're correct about this. I did some more archeology and that (missing symbols in most existing libraries) seems to be the reason why `-fsized-deallocation` wasn't made default for so long. And since the sized `operator delete` does call the normal `operator delete`, you're also correct that there shouldn't be a backwards compatibility issue here. The situation we're running into downstream probably calls for a different solution. > Do you mean we'd have them if there are back-deployment problems? Because I can't find any. Ah, you're right here too, I wrongly assumed there were availability attributes. That looks like an oversight, since availability attributes are definitely the way we'd normally catch these kinds of issues. Either way, I think I'm convinced that the current code is the way it should be, so I'll close this. Thanks for the discussion. We will pursue another direction for the downstream issues we saw related to this. https://github.com/llvm/llvm-project/pull/125577 From libcxx-commits at lists.llvm.org Wed Feb 5 06:21:25 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Wed, 05 Feb 2025 06:21:25 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Avoid including on arbitrary platforms (PR #125587) In-Reply-To: Message-ID: <67a373e5.620a0220.2995a1.8ea0@mx.google.com> https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/125587 >From 21ff2ef0cab9edc79ac01a128998aa0c0bce8f83 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 3 Feb 2025 16:23:12 -0500 Subject: [PATCH 1/2] [libc++] Avoid including on arbitrary platforms This partially reverts commit 5f2389d4. That commit started checking whether was a valid include unconditionally, however codebases are free to have such a header on their search path, which breaks compilation. LLVM libc should instead provide a more standard way of getting configuration macros like __LLVM_LIBC__. After this patch, we only include when we're on Linux or when we're compiling for GPUs. --- libcxx/include/__configuration/platform.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libcxx/include/__configuration/platform.h b/libcxx/include/__configuration/platform.h index 2a92ce209b91f8b..cff99376ee24b12 100644 --- a/libcxx/include/__configuration/platform.h +++ b/libcxx/include/__configuration/platform.h @@ -30,12 +30,9 @@ // ... add new file formats here ... #endif -// To detect which libc we're using -#if __has_include() +// Need to detect which libc we're using if we're on Linux. +#if defined(__linux__) || defined(__AMDGPU__) || defined(__NVPTX__) # include -#endif - -#if defined(__linux__) # if defined(__GLIBC_PREREQ) # define _LIBCPP_GLIBC_PREREQ(a, b) __GLIBC_PREREQ(a, b) # else >From 832ff608e9e0623785afa6cb6f61cb292fb86213 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 5 Feb 2025 09:21:14 -0500 Subject: [PATCH 2/2] Poke CI From libcxx-commits at lists.llvm.org Wed Feb 5 06:23:57 2025 From: libcxx-commits at lists.llvm.org (via libcxx-commits) Date: Wed, 05 Feb 2025 06:23:57 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Reduce std::conjunction overhead (PR #124259) In-Reply-To: Message-ID: <67a3747d.a70a0220.34e3b8.a77d@mx.google.com> eaeltsin wrote: We might have overreduced the test, but ended up with the following code that makes the compiler exhaust the stack and SIGSEGV: ``` template struct _AndImpl { template using _Result = _AndImpl::template _Result<_First>; }; template using _And = _AndImpl::template _Result; _And<>; ``` not yet sure which usage of `std::conjunction` leads to this. https://github.com/llvm/llvm-project/pull/124259 From libcxx-commits at lists.llvm.org Wed Feb 5 06:28:49 2025 From: libcxx-commits at lists.llvm.org (Louis Dionne via libcxx-commits) Date: Wed, 05 Feb 2025 06:28:49 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Avoid including on arbitrary platforms (PR #125587) In-Reply-To: Message-ID: <67a375a1.170a0220.9d35a.4aa7@mx.google.com> ldionne wrote: > This is going to break other platforms supported by LLVM libc, most notably baremetal (for which we don't really have a great detection mechanism since there's no OS). > > An alternative to using an LLVM libc provided header would be to store the value of [`LIBCXX_LIBC`](https://github.com/llvm/llvm-project/blob/646d352ab0d0a9cfafa3f2c9c415b5773834ad5b/libcxx/CMakeLists.txt#L231) CMake option in `__config_site` and then use that. This could also eventually replace [`_LIBCPP_HAS_MUSL_LIBC`](https://github.com/llvm/llvm-project/blob/646d352ab0d0a9cfafa3f2c9c415b5773834ad5b/libcxx/include/__config_site.in#L19). At first glance, I'm really not a huge fan of hardcoding the libc we're building on top of in `__config_site`. However, I do think that this is potentially a more elegant approach than what we do right now (a mix of `_LIBCPP_HAS_MUSL_LIBC` and auto-detection), and it would also solve some problems we have downstream so I think this might be generally useful. I'm willing to work on that, but it's not something we'd be able to cherry-pick back to LLVM 20 given its complexity and the time it'll take to put something together. In the meantime, I think it's pretty urgent to restore to a behavior that works on mainstream platforms. If you have specific concerns about this patch breaking some new setups since the last release, perhaps we can carve them out using additional `#ifdef`s? https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Wed Feb 5 06:30:38 2025 From: libcxx-commits at lists.llvm.org (Joseph Huber via libcxx-commits) Date: Wed, 05 Feb 2025 06:30:38 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Avoid including on arbitrary platforms (PR #125587) In-Reply-To: Message-ID: <67a3760e.a70a0220.36d3b7.ad91@mx.google.com> jhuber6 wrote: I'm personally not concerned with the GPU stuff being broken on Clang-20 since the support is still experimental and I doubt anyone's depending on it. https://github.com/llvm/llvm-project/pull/125587 From libcxx-commits at lists.llvm.org Wed Feb 5 07:02:14 2025 From: libcxx-commits at lists.llvm.org (Nikolas Klauser via libcxx-commits) Date: Wed, 05 Feb 2025 07:02:14 -0800 (PST) Subject: [libcxx-commits] [libcxx] [libc++] Optimize std::getline (PR #121346) In-Reply-To: Message-ID: <67a37d76.170a0220.3908ac.b5a3@mx.google.com> https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/121346 >From 7075d55afa816629bf33db72f6a15449969dc45c Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Mon, 30 Dec 2024 16:57:54 +0100 Subject: [PATCH] [libc++] Optimize std::getline ``` ----------------------------------------------- Benchmark old new ----------------------------------------------- BM_getline_string 318 ns 32.4 ns ``` --- libcxx/docs/ReleaseNotes/20.rst | 2 + libcxx/include/istream | 77 ++++++---- libcxx/include/streambuf | 7 + .../test/benchmarks/streams/getline.bench.cpp | 35 +++++ .../string.io/get_line.pass.cpp | 137 ++++++++---------- libcxx/test/support/stream_types.h | 44 ++++++ 6 files changed, 196 insertions(+), 106 deletions(-) create mode 100644 libcxx/test/benchmarks/streams/getline.bench.cpp create mode 100644 libcxx/test/support/stream_types.h diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst index c8a07fb8b733484..05881722672ddab 100644 --- a/libcxx/docs/ReleaseNotes/20.rst +++ b/libcxx/docs/ReleaseNotes/20.rst @@ -73,6 +73,8 @@ Improvements and New Features optimized, resulting in a performance improvement of up to 2x for trivial element types (e.g., `std::vector`), and up to 3.4x for non-trivial element types (e.g., `std::vector>`). +- The performance of ``std::getline`` has been improved, resulting in a performance uplift of up to 10x. + Deprecations and Removals ------------------------- diff --git a/libcxx/include/istream b/libcxx/include/istream index 4b177c41cc325e0..a9fd81d34786b3a 100644 --- a/libcxx/include/istream +++ b/libcxx/include/istream @@ -1265,41 +1265,66 @@ _LIBCPP_HIDE_FROM_ABI basic_istream<_CharT, _Traits>& getline(basic_istream<_CharT, _Traits>& __is, basic_string<_CharT, _Traits, _Allocator>& __str, _CharT __dlm) { ios_base::iostate __state = ios_base::goodbit; typename basic_istream<_CharT, _Traits>::sentry __sen(__is, true); - if (__sen) { + if (!__sen) + return __is; # if _LIBCPP_HAS_EXCEPTIONS - try { + try { # endif - __str.clear(); - streamsize __extr = 0; - while (true) { - typename _Traits::int_type __i = __is.rdbuf()->sbumpc(); - if (_Traits::eq_int_type(__i, _Traits::eof())) { - __state |= ios_base::eofbit; - break; + __str.clear(); + + auto& __buffer = *__is.rdbuf(); + + auto __next = __buffer.sgetc(); + for (; !_Traits::eq_int_type(__next, _Traits::eof()); __next = __buffer.sgetc()) { + const auto* __first = __buffer.gptr(); + const auto* __last = __buffer.egptr(); + _CharT __1buf; + + if (__first == __last) { + __1buf = __next; + __first = &__1buf; + __last = &__1buf + 1; + } + + auto __bump_stream = [&](ptrdiff_t __diff) { + if (__first == &__1buf) { + _LIBCPP_ASSERT_INTERNAL(__diff == 1, "trying to bump stream further than buffer size"); + __buffer.sbumpc(); + } else { + __buffer.__gbump_ptrdiff(__diff); } - ++__extr; - _CharT __ch = _Traits::to_char_type(__i); - if (_Traits::eq(__ch, __dlm)) - break; - __str.push_back(__ch); - if (__str.size() == __str.max_size()) { + }; + + const auto* __match = _Traits::find(__first, __last - __first, __dlm); + if (__match) { + if (auto __cap = __str.max_size() - __str.size(); __cap > static_cast(__match - __first)) { + __str.append(__first, __match); + __bump_stream(__match - __first + 1); + } else { + __str.append(__first, __cap); + __bump_stream(__cap); __state |= ios_base::failbit; - break; } + break; } - if (__extr == 0) - __state |= ios_base::failbit; + + __str.append(__first, __last); + __bump_stream(__last - __first); + } + + if (_Traits::eq_int_type(__next, _Traits::eof())) + __state |= ios_base::eofbit | (__str.empty() ? ios_base::failbit : ios_base::goodbit); + # if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __state |= ios_base::badbit; - __is.__setstate_nothrow(__state); - if (__is.exceptions() & ios_base::badbit) { - throw; - } + } catch (...) { + __state |= ios_base::badbit; + __is.__setstate_nothrow(__state); + if (__is.exceptions() & ios_base::badbit) { + throw; } -# endif - __is.setstate(__state); } +# endif + __is.setstate(__state); return __is; } diff --git a/libcxx/include/streambuf b/libcxx/include/streambuf index 7f02a9b33141100..a3e1cf489d0efa9 100644 --- a/libcxx/include/streambuf +++ b/libcxx/include/streambuf @@ -241,6 +241,9 @@ protected: inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void gbump(int __n) { __ninp_ += __n; } + // gbump takes an int, so it might not be able to represent the offset we want to add. + _LIBCPP_HIDE_FROM_ABI void __gbump_ptrdiff(ptrdiff_t __n) { __ninp_ += __n; } + inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void setg(char_type* __gbeg, char_type* __gnext, char_type* __gend) { _LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gnext), "[gbeg, gnext) must be a valid range"); _LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gend), "[gbeg, gend) must be a valid range"); @@ -297,6 +300,10 @@ private: char_type* __bout_; char_type* __nout_; char_type* __eout_; + + template + _LIBCPP_HIDE_FROM_ABI friend basic_istream<_CharT2, _Traits2>& + getline(basic_istream<_CharT2, _Traits2>&, basic_string<_CharT2, _Traits2, _Allocator>&, _CharT2); }; template diff --git a/libcxx/test/benchmarks/streams/getline.bench.cpp b/libcxx/test/benchmarks/streams/getline.bench.cpp new file mode 100644 index 000000000000000..6a2215fe061167b --- /dev/null +++ b/libcxx/test/benchmarks/streams/getline.bench.cpp @@ -0,0 +1,35 @@ + +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03 + +#include +#include + +#include + +void BM_getline_string(benchmark::State& state) { + std::istringstream iss; + + std::string str; + str.reserve(128); + iss.str("A long string to let getline do some more work, making sure that longer strings are parsed fast enough"); + + for (auto _ : state) { + benchmark::DoNotOptimize(iss); + + std::getline(iss, str); + benchmark::DoNotOptimize(str); + iss.seekg(0); + } +} + +BENCHMARK(BM_getline_string); + +BENCHMARK_MAIN(); diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string.io/get_line.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string.io/get_line.pass.cpp index 7bcb34135440bfb..2dee62df14b42cc 100644 --- a/libcxx/test/std/strings/basic.string/string.nonmembers/string.io/get_line.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string.io/get_line.pass.cpp @@ -13,55 +13,42 @@ // getline(basic_istream& is, // basic_string& str); -#include -#include #include +#include +#include +#include "make_string.h" #include "min_allocator.h" +#include "stream_types.h" #include "test_macros.h" -template