aboutsummaryrefslogtreecommitdiff
path: root/libcxx
diff options
context:
space:
mode:
Diffstat (limited to 'libcxx')
-rw-r--r--libcxx/.clang-format1
-rw-r--r--libcxx/cmake/caches/Generic-hardening-mode-extensive-observe-semantic.cmake2
-rw-r--r--libcxx/docs/Hardening.rst68
-rw-r--r--libcxx/docs/ReleaseNotes.rst3
-rw-r--r--libcxx/docs/ReleaseNotes/21.rst6
-rw-r--r--libcxx/docs/ReleaseNotes/22.rst59
-rw-r--r--libcxx/docs/Status/Cxx23Issues.csv6
-rw-r--r--libcxx/docs/UserDocumentation.rst5
-rw-r--r--libcxx/include/CMakeLists.txt4
-rw-r--r--libcxx/include/__algorithm/copy.h4
-rw-r--r--libcxx/include/__algorithm/copy_backward.h4
-rw-r--r--libcxx/include/__algorithm/find.h2
-rw-r--r--libcxx/include/__algorithm/for_each.h2
-rw-r--r--libcxx/include/__algorithm/for_each_n.h6
-rw-r--r--libcxx/include/__algorithm/for_each_n_segment.h2
-rw-r--r--libcxx/include/__algorithm/move.h4
-rw-r--r--libcxx/include/__algorithm/move_backward.h4
-rw-r--r--libcxx/include/__config103
-rw-r--r--libcxx/include/__cxx03/__config4
-rw-r--r--libcxx/include/__flat_map/flat_multimap.h355
-rw-r--r--libcxx/include/__format/concepts.h14
-rw-r--r--libcxx/include/__format/fmt_pair_like.h42
-rw-r--r--libcxx/include/__format/range_default_formatter.h1
-rw-r--r--libcxx/include/__format/range_format.h2
-rw-r--r--libcxx/include/__format/range_formatter.h1
-rw-r--r--libcxx/include/__functional/bind.h21
-rw-r--r--libcxx/include/__iterator/segmented_iterator.h6
-rw-r--r--libcxx/include/__log_hardening_failure42
-rw-r--r--libcxx/include/__memory/construct_at.h6
-rw-r--r--libcxx/include/__memory_resource/polymorphic_allocator.h10
-rw-r--r--libcxx/include/__mutex/once_flag.h11
-rw-r--r--libcxx/include/__ranges/zip_transform_view.h357
-rw-r--r--libcxx/include/__ranges/zip_view.h8
-rw-r--r--libcxx/include/__thread/thread.h7
-rw-r--r--libcxx/include/__tuple/make_tuple_types.h25
-rw-r--r--libcxx/include/__tuple/tuple_element.h1
-rw-r--r--libcxx/include/__tuple/tuple_indices.h37
-rw-r--r--libcxx/include/__utility/integer_sequence.h68
-rw-r--r--libcxx/include/__utility/pair.h10
-rw-r--r--libcxx/include/__vector/vector.h61
-rw-r--r--libcxx/include/__vector/vector_bool.h63
-rw-r--r--libcxx/include/bitset10
-rw-r--r--libcxx/include/deque5
-rw-r--r--libcxx/include/future9
-rw-r--r--libcxx/include/module.modulemap.in8
-rw-r--r--libcxx/include/mutex7
-rw-r--r--libcxx/include/print14
-rw-r--r--libcxx/include/ranges11
-rw-r--r--libcxx/include/regex2
-rw-r--r--libcxx/include/scoped_allocator10
-rw-r--r--libcxx/include/string45
-rw-r--r--libcxx/include/string_view52
-rw-r--r--libcxx/include/tuple119
-rw-r--r--libcxx/include/variant4
-rw-r--r--libcxx/modules/std/ranges.inc4
-rw-r--r--libcxx/src/CMakeLists.txt1
-rw-r--r--libcxx/src/experimental/log_hardening_failure.cpp31
-rw-r--r--libcxx/test/extensions/gnu/hash_map/hash_map.pass.cpp (renamed from libcxx/test/libcxx/containers/gnu_cxx/hash_map.pass.cpp)0
-rw-r--r--libcxx/test/extensions/gnu/hash_map/hash_map_name_lookup.pass.cpp (renamed from libcxx/test/libcxx/containers/gnu_cxx/hash_map_name_lookup.pass.cpp)0
-rw-r--r--libcxx/test/extensions/gnu/hash_set/hash_set.pass.cpp (renamed from libcxx/test/libcxx/containers/gnu_cxx/hash_set.pass.cpp)0
-rw-r--r--libcxx/test/extensions/gnu/hash_set/hash_set_name_lookup.pass.cpp (renamed from libcxx/test/libcxx/containers/gnu_cxx/hash_set_name_lookup.pass.cpp)0
-rw-r--r--libcxx/test/extensions/libcxx/atomics/atomics.flag/init_bool.pass.cpp (renamed from libcxx/test/libcxx/atomics/atomics.flag/init_bool.pass.cpp)0
-rw-r--r--libcxx/test/extensions/libcxx/containers/associative/map/scary.compile.pass.cpp (renamed from libcxx/test/libcxx/containers/associative/map/scary.compile.pass.cpp)0
-rw-r--r--libcxx/test/extensions/libcxx/containers/associative/set/scary.compile.pass.cpp (renamed from libcxx/test/libcxx/containers/associative/set/scary.compile.pass.cpp)0
-rw-r--r--libcxx/test/extensions/libcxx/containers/associative/unord.map/scary.compile.pass.cpp (renamed from libcxx/test/libcxx/containers/associative/unord.map/scary.compile.pass.cpp)0
-rw-r--r--libcxx/test/extensions/libcxx/containers/associative/unord.set/scary.compile.pass.cpp (renamed from libcxx/test/libcxx/containers/associative/unord.set/scary.compile.pass.cpp)0
-rw-r--r--libcxx/test/extensions/libcxx/containers/sequences/deque/incomplete.pass.cpp (renamed from libcxx/test/libcxx/containers/sequences/deque/incomplete.pass.cpp)0
-rw-r--r--libcxx/test/extensions/libcxx/depr/depr.c.headers/extern_c.pass.cpp (renamed from libcxx/test/libcxx/depr/depr.c.headers/extern_c.pass.cpp)0
-rw-r--r--libcxx/test/extensions/libcxx/depr/depr.c.headers/include_as_c.sh.cpp (renamed from libcxx/test/extensions/libcxx/include_as_c.sh.cpp)0
-rw-r--r--libcxx/test/extensions/libcxx/depr/depr.c.headers/stdint_h.std_types_t.compile.pass.cpp (renamed from libcxx/test/libcxx/depr/depr.c.headers/stdint_h.std_types_t.compile.pass.cpp)0
-rw-r--r--libcxx/test/extensions/libcxx/depr/depr.c.headers/stdint_h.xopen_source.compile.pass.cpp (renamed from libcxx/test/libcxx/depr/depr.c.headers/stdint_h.xopen_source.compile.pass.cpp)0
-rw-r--r--libcxx/test/extensions/msvc/math_h.compile.pass.cpp (renamed from libcxx/test/libcxx/depr/depr.c.headers/math_h.compile.pass.cpp)0
-rw-r--r--libcxx/test/libcxx/algorithms/specialized.algorithms/nonnull.verify.cpp28
-rw-r--r--libcxx/test/libcxx/assertions/log_hardening_failure.pass.cpp26
-rw-r--r--libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp4
-rw-r--r--libcxx/test/libcxx/containers/sequences/deque/spare_block_handling.pass.cpp8
-rw-r--r--libcxx/test/libcxx/containers/sequences/forwardlist/bool-conversion.pass.cpp37
-rw-r--r--libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp56
-rw-r--r--libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp59
-rw-r--r--libcxx/test/libcxx/diagnostics/vector.nodiscard.verify.cpp43
-rw-r--r--libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp4
-rw-r--r--libcxx/test/libcxx/input.output/iostream.format/print.fun/nonnull.verify.cpp23
-rw-r--r--libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp2
-rw-r--r--libcxx/test/libcxx/ranges/range.adaptors/range.zip.transform/no_unique_address.compile.pass.cpp32
-rw-r--r--libcxx/test/libcxx/strings/basic.string/nonnull.verify.cpp25
-rw-r--r--libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp3
-rw-r--r--libcxx/test/libcxx/strings/string.view/nonnull.verify.cpp53
-rw-r--r--libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp2
-rw-r--r--libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp2
-rw-r--r--libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp20
-rw-r--r--libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp20
-rw-r--r--libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp4
-rw-r--r--libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp4
-rw-r--r--libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp4
-rw-r--r--libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp4
-rw-r--r--libcxx/test/std/containers/associative/map/find.modules.compile.pass.mm (renamed from libcxx/test/libcxx/containers/associative/map/find.modules.compile.pass.mm)0
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/empty.pass.cpp18
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/max_size.pass.cpp12
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/size.pass.cpp21
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/alloc.pass.cpp48
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/assign_initializer_list.pass.cpp41
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/compare.pass.cpp108
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/containers.pass.cpp207
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy.pass.cpp36
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_alloc.pass.cpp58
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_assign.pass.cpp56
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default.pass.cpp40
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default_noexcept.pass.cpp15
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/dtor_noexcept.pass.cpp43
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/initializer_list.pass.cpp160
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/iter_iter.pass.cpp231
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move.pass.cpp34
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_alloc.pass.cpp76
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign.pass.cpp35
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_clears.pass.cpp65
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_noexcept.compile.pass.cpp (renamed from libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_noexcept.pass.cpp)4
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/range.pass.cpp287
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_container.pass.cpp139
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_initializer_list.pass.cpp164
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_iter_iter.pass.cpp165
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.erasure/erase_if.pass.cpp28
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator.pass.cpp18
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_comparison.pass.cpp18
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/reverse_iterator.pass.cpp98
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/clear.pass.cpp17
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace.pass.cpp27
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace_hint.pass.cpp29
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter.pass.cpp59
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter_iter.pass.cpp34
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key.pass.cpp19
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key_transparent.pass.cpp42
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/extract.pass.cpp27
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_cv.pass.cpp20
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_initializer_list.pass.cpp24
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_cv.pass.cpp20
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_iter.pass.cpp27
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_rv.pass.cpp25
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range.pass.cpp22
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_rv.pass.cpp21
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_initializer_list.pass.cpp23
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_iter_iter.pass.cpp19
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_transparent.pass.cpp120
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/replace.pass.cpp21
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp17
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp18
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp16
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/keys_values.pass.cpp31
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains.pass.cpp17
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains_transparent.pass.cpp19
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count.pass.cpp18
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count_transparent.pass.cpp18
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range.pass.cpp17
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range_transparent.pass.cpp20
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find.pass.cpp17
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find_transparent.pass.cpp17
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound.pass.cpp17
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound_transparent.pass.cpp17
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound.pass.cpp17
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound_transparent.pass.cpp17
-rw-r--r--libcxx/test/std/containers/container.adaptors/flat.multimap/helpers.h11
-rw-r--r--libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp19
-rw-r--r--libcxx/test/std/containers/sequences/vector/erase.modules.compile.pass.mm (renamed from libcxx/test/libcxx/containers/sequences/vector/erase.modules.compile.pass.mm)0
-rw-r--r--libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp31
-rw-r--r--libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp33
-rw-r--r--libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp4
-rw-r--r--libcxx/test/std/experimental/simd/simd.class/simd_unary.pass.cpp4
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array.pass.cpp5
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.pass.cpp5
-rw-r--r--libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp53
-rw-r--r--libcxx/test/std/numerics/c.math/signbit.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/begin.pass.cpp127
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/cpo.pass.cpp159
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctad.compile.pass.cpp41
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctor.default.pass.cpp147
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctor.views.pass.cpp144
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/end.pass.cpp147
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/general.pass.cpp29
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/arithmetic.pass.cpp237
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/compare.pass.cpp226
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/ctor.default.pass.cpp57
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/ctor.other.pass.cpp131
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/decrement.pass.cpp139
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/deref.pass.cpp143
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/increment.pass.cpp133
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/member_types.compile.pass.cpp169
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/subscript.pass.cpp91
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/ctor.default.pass.cpp55
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/ctor.other.pass.cpp159
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/eq.pass.cpp199
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/minus.pass.cpp279
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/size.pass.cpp128
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip.transform/types.h58
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/begin.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/cpo.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/ctor.views.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/end.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/arithmetic.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/compare.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/ctor.default.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/ctor.other.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/decrement.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/deref.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/iter_move.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/iter_swap.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/member_types.compile.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/singular.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/iterator/subscript.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/range.concept.compile.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/ctor.other.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/eq.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/minus.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range.zip/size.pass.cpp2
-rw-r--r--libcxx/test/std/ranges/range.adaptors/range_adaptor_types.h (renamed from libcxx/test/std/ranges/range.adaptors/range.zip/types.h)126
-rw-r--r--libcxx/test/std/ranges/ranges_robust_against_no_unique_address.pass.cpp1
-rw-r--r--libcxx/test/std/re/re.regex/re.regex.construct/bad_range.pass.cpp5
-rw-r--r--libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/shared_ptr_array.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp2
-rw-r--r--libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp2
-rw-r--r--libcxx/test/support/check_assertion.h137
-rw-r--r--libcxx/test/support/test.support/test_check_assertion.pass.cpp20
-rw-r--r--libcxx/utils/ci/Dockerfile22
-rw-r--r--libcxx/utils/ci/docker-compose.yml14
-rwxr-xr-xlibcxx/utils/ci/run-buildbot6
-rw-r--r--libcxx/utils/libcxx/test/params.py20
-rwxr-xr-xlibcxx/utils/synchronize_csv_status_files.py8
-rw-r--r--libcxx/vendor/llvm/default_assertion_handler.in35
231 files changed, 7175 insertions, 1786 deletions
diff --git a/libcxx/.clang-format b/libcxx/.clang-format
index f372ac9..9557b95 100644
--- a/libcxx/.clang-format
+++ b/libcxx/.clang-format
@@ -33,6 +33,7 @@ AttributeMacros: [
'_LIBCPP_DEPRECATED_IN_CXX20',
'_LIBCPP_DEPRECATED_IN_CXX23',
'_LIBCPP_DEPRECATED',
+ '_LIBCPP_DIAGNOSE_NULLPTR_IF',
'_LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION',
'_LIBCPP_EXPORTED_FROM_ABI',
'_LIBCPP_EXTERN_TEMPLATE_TYPE_VIS',
diff --git a/libcxx/cmake/caches/Generic-hardening-mode-extensive-observe-semantic.cmake b/libcxx/cmake/caches/Generic-hardening-mode-extensive-observe-semantic.cmake
new file mode 100644
index 0000000..c843c02
--- /dev/null
+++ b/libcxx/cmake/caches/Generic-hardening-mode-extensive-observe-semantic.cmake
@@ -0,0 +1,2 @@
+set(LIBCXX_HARDENING_MODE "extensive" CACHE STRING "")
+set(LIBCXX_TEST_PARAMS "assertion_semantic=observe" CACHE STRING "")
diff --git a/libcxx/docs/Hardening.rst b/libcxx/docs/Hardening.rst
index 1780884..1cdb360 100644
--- a/libcxx/docs/Hardening.rst
+++ b/libcxx/docs/Hardening.rst
@@ -39,6 +39,8 @@ modes are:
Enabling hardening has no impact on the ABI.
+.. _notes-for-users:
+
Notes for users
---------------
@@ -72,6 +74,10 @@ to control the level by passing **one** of the following options to the compiler
pre-built components. Most libc++ code is header-based, so a user-provided
value for ``_LIBCPP_HARDENING_MODE`` will be mostly respected.
+In some cases, users might want to override the assertion semantic used by the
+library. This can be done similarly to setting the hardening mode; please refer
+to the :ref:`relevant section <assertion-semantics>`.
+
Notes for vendors
-----------------
@@ -260,6 +266,68 @@ output. This is less secure and increases the size of the binary (among other
things, it has to store the error message strings) but makes the failure easier
to debug. It also allows testing the error messages in our test suite.
+This default behavior can be customized by users via :ref:`assertion semantics
+<assertion-semantics>`; it can also be completely overridden by vendors by
+providing a :ref:`custom assertion failure handler
+<override-assertion-handler>`.
+
+.. _assertion-semantics:
+
+Assertion semantics
+-------------------
+
+.. warning::
+
+ Assertion semantics are currently an experimental feature.
+
+.. note::
+
+ Assertion semantics are not available in the C++03 mode.
+
+What happens when an assertion fails depends on the assertion semantic being
+used. Four assertion semantics are available, based on C++26 Contracts
+evaluation semantics:
+
+- ``ignore`` evaluates the assertion but has no effect if it fails (note that it
+ differs from the Contracts ``ignore`` semantic which would not evaluate
+ the assertion at all);
+- ``observe`` logs an error (indicating, if possible on the platform, that the
+ error is fatal) but continues execution;
+- ``quick-enforce`` terminates the program as fast as possible via a trap
+ instruction. It is the default semantic for the production modes (``fast`` and
+ ``extensive``);
+- ``enforce`` logs an error and then terminates the program. It is the default
+ semantic for the ``debug`` mode.
+
+Notes:
+
+- Continuing execution after a hardening check fails results in undefined
+ behavior; the ``observe`` semantic is meant to make adopting hardening easier
+ but should not be used outside of the adoption period;
+- C++26 wording for Library Hardening precludes a conforming Hardened
+ implementation from using the Contracts ``ignore`` semantic when evaluating
+ hardened preconditions in the Library. Libc++ allows using this semantic for
+ hardened preconditions, but please be aware that using ``ignore`` does not
+ produce a conforming "Hardened" implementation, unlike the other semantics
+ above.
+
+The default assertion semantics are as follows:
+
+- ``fast``: ``quick-enforce``;
+- ``extensive``: ``quick-enforce``;
+- ``debug``: ``enforce``.
+
+The default assertion semantics can be overridden by passing **one** of the
+following options to the compiler:
+
+- ``-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE``
+- ``-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE``
+- ``-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE``
+- ``-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE``
+
+All the :ref:`same notes <notes-for-users>` apply to setting this macro as for
+setting ``_LIBCPP_HARDENING_MODE``.
+
.. _override-assertion-handler:
Overriding the assertion failure handler
diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index 9feea5f..acfcd36 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -1,10 +1,11 @@
-.. include:: ReleaseNotes/21.rst
+.. include:: ReleaseNotes/22.rst
.. Make sure to reference the non-live release notes in a toctree to avoid Sphinx errors.
.. toctree::
:hidden:
ReleaseNotes/20
+ ReleaseNotes/21
.. The release notes are in versioned files, but we make sure to keep publishing
.. them in an unversioned ReleaseNotes.html page for external sites to reference.
diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst
index d31ca01..74bfa97 100644
--- a/libcxx/docs/ReleaseNotes/21.rst
+++ b/libcxx/docs/ReleaseNotes/21.rst
@@ -88,6 +88,12 @@ Improvements and New Features
- ``ctype::tolower`` and ``ctype::toupper`` have been optimized, resulting in a 2x performance improvement.
+- As an experimental feature, Hardening now supports assertion semantics that allow customizing how a hardening
+ assertion failure is handled. The four available semantics, modeled on C++26 Contracts, are ``ignore``, ``observe``,
+ ``quick-enforce`` and ``enforce``. The ``observe`` semantic is intended to make it easier to adopt Hardening in
+ production but should not be used outside of this scenario. Please refer to the :ref:`Hardening documentation
+ <hardening>` for details.
+
Deprecations and Removals
-------------------------
diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
new file mode 100644
index 0000000..15bf46d
--- /dev/null
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -0,0 +1,59 @@
+===========================================
+Libc++ 22.0.0 (In-Progress) Release Notes
+===========================================
+
+.. contents::
+ :local:
+ :depth: 2
+
+Written by the `Libc++ Team <https://libcxx.llvm.org>`_
+
+.. warning::
+
+ These are in-progress notes for the upcoming libc++ 22.0.0 release.
+ Release notes for previous releases can be found on
+ `the Download Page <https://releases.llvm.org/download.html>`_.
+
+Introduction
+============
+
+This document contains the release notes for the libc++ C++ Standard Library,
+part of the LLVM Compiler Infrastructure, release 22.0.0. Here we describe the
+status of libc++ in some detail, including major improvements from the previous
+release and new feature work. For the general LLVM release notes, see `the LLVM
+documentation <https://llvm.org/docs/ReleaseNotes.html>`_. All LLVM releases may
+be downloaded from the `LLVM releases web site <https://llvm.org/releases/>`_.
+
+For more information about libc++, please see the `Libc++ Web Site
+<https://libcxx.llvm.org>`_ or the `LLVM Web Site <https://llvm.org>`_.
+
+Note that if you are reading this file from a Git checkout or the
+main Libc++ web page, this document applies to the *next* release, not
+the current one. To see the release notes for a specific release, please
+see the `releases page <https://llvm.org/releases/>`_.
+
+What's New in Libc++ 22.0.0?
+==============================
+
+Implemented Papers
+------------------
+
+- P2321R2: ``zip`` (`Github <https://github.com/llvm/llvm-project/issues/105169>`__) (The paper is partially implemented. ``zip_transform_view`` is implemented in this release)
+
+Improvements and New Features
+-----------------------------
+
+Deprecations and Removals
+-------------------------
+
+Potentially breaking changes
+----------------------------
+
+Announcements About Future Releases
+-----------------------------------
+
+ABI Affecting Changes
+---------------------
+
+Build System Changes
+--------------------
diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index e5b2dcf..189f845 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -170,7 +170,7 @@
"`LWG3687 <https://wg21.link/LWG3687>`__","``expected<cv void, E>`` move constructor should move","2022-07 (Virtual)","|Complete|","16",""
"`LWG3692 <https://wg21.link/LWG3692>`__","``zip_view::iterator``'s ``operator<=>`` is overconstrained","2022-07 (Virtual)","|Complete|","20",""
"`LWG3701 <https://wg21.link/LWG3701>`__","Make ``formatter<remove_cvref_t<const charT[N]>, charT>`` requirement explicit","2022-07 (Virtual)","|Complete|","15",""
-"`LWG3702 <https://wg21.link/LWG3702>`__","Should ``zip_transform_view::iterator`` remove ``operator<``","2022-07 (Virtual)","","",""
+"`LWG3702 <https://wg21.link/LWG3702>`__","Should ``zip_transform_view::iterator`` remove ``operator<``","2022-07 (Virtual)","|Complete|","22",""
"`LWG3703 <https://wg21.link/LWG3703>`__","Missing requirements for ``expected<T, E>`` requires ``is_void<T>``","2022-07 (Virtual)","|Complete|","16",""
"`LWG3704 <https://wg21.link/LWG3704>`__","LWG 2059 added overloads that might be ill-formed for sets","2022-07 (Virtual)","","",""
"`LWG3705 <https://wg21.link/LWG3705>`__","Hashability shouldn't depend on basic_string's allocator","2022-07 (Virtual)","|Complete|","16",""
@@ -222,7 +222,7 @@
"`LWG3765 <https://wg21.link/LWG3765>`__","``const_sentinel`` should be constrained","2022-11 (Kona)","","",""
"`LWG3766 <https://wg21.link/LWG3766>`__","``view_interface::cbegin`` is underconstrained","2022-11 (Kona)","","",""
"`LWG3770 <https://wg21.link/LWG3770>`__","``const_sentinel_t`` is missing","2022-11 (Kona)","","",""
-"`LWG3773 <https://wg21.link/LWG3773>`__","``views::zip_transform`` still requires ``F`` to be ``copy_constructible`` when empty pack","2022-11 (Kona)","","",""
+"`LWG3773 <https://wg21.link/LWG3773>`__","``views::zip_transform`` still requires ``F`` to be ``copy_constructible`` when empty pack","2022-11 (Kona)","|Complete|","22",""
"`LWG3774 <https://wg21.link/LWG3774>`__","``<flat_set>`` should include ``<compare>``","2022-11 (Kona)","","",""
"`LWG3775 <https://wg21.link/LWG3775>`__","Broken dependencies in the ``Cpp17Allocator`` requirements","2022-11 (Kona)","","",""
"`LWG3778 <https://wg21.link/LWG3778>`__","``vector<bool>`` missing exception specifications","2022-11 (Kona)","|Complete|","3.7",""
@@ -234,7 +234,7 @@
"`LWG3792 <https://wg21.link/LWG3792>`__","``__cpp_lib_constexpr_algorithms`` should also be defined in ``<utility>``","2022-11 (Kona)","|Complete|","16",""
"`LWG3795 <https://wg21.link/LWG3795>`__","Self-move-assignment of ``std::future`` and ``std::shared_future`` have unimplementable postconditions","2022-11 (Kona)","","",""
"`LWG3796 <https://wg21.link/LWG3796>`__","``movable-box`` as member should use ``default-initialization`` instead of ``copy-initialization``","2022-11 (Kona)","","",""
-"`LWG3798 <https://wg21.link/LWG3798>`__","Rvalue reference and ``iterator_category``","2022-11 (Kona)","|Partial|","","``join_with_view``, ``zip_transform_view``, and ``adjacent_transform_view`` haven't been done yet since these types aren't implemented yet"
+"`LWG3798 <https://wg21.link/LWG3798>`__","Rvalue reference and ``iterator_category``","2022-11 (Kona)","|Partial|","","``adjacent_transform_view`` hasn't been done yet since this type isn't implemented yet"
"`LWG3801 <https://wg21.link/LWG3801>`__","``cartesian_product_view::iterator::distance-from`` ignores the size of last underlying range","2022-11 (Kona)","","",""
"`LWG3814 <https://wg21.link/LWG3814>`__","Add freestanding items requested by NB comments","2022-11 (Kona)","","",""
"`LWG3816 <https://wg21.link/LWG3816>`__","``flat_map`` and ``flat_multimap`` should impose sequence container requirements","2022-11 (Kona)","","",""
diff --git a/libcxx/docs/UserDocumentation.rst b/libcxx/docs/UserDocumentation.rst
index 79f5908..415a599 100644
--- a/libcxx/docs/UserDocumentation.rst
+++ b/libcxx/docs/UserDocumentation.rst
@@ -72,6 +72,11 @@ when ``-fexperimental-library`` is passed:
* ``std::chrono::tzdb`` and related time zone functionality
* ``<syncstream>``
+Additionally, assertion semantics are an experimental feature that can be used
+to customize the behavior of Hardening (see :ref:`here <assertion-semantics>`).
+Assertion semantics mirror the evaluation semantics of C++26 Contracts but are
+not a standard feature.
+
.. note::
Experimental libraries are experimental.
* The contents of the ``<experimental/...>`` headers and the associated static
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 25b567df..51444ec 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -381,6 +381,7 @@ set(files
__format/enable_insertable.h
__format/escaped_output_table.h
__format/extended_grapheme_cluster_table.h
+ __format/fmt_pair_like.h
__format/format_arg.h
__format/format_arg_store.h
__format/format_args.h
@@ -535,6 +536,7 @@ set(files
__locale_dir/time.h
__locale_dir/wbuffer_convert.h
__locale_dir/wstring_convert.h
+ __log_hardening_failure
__math/abs.h
__math/copysign.h
__math/error_functions.h
@@ -737,6 +739,7 @@ set(files
__ranges/transform_view.h
__ranges/view_interface.h
__ranges/views.h
+ __ranges/zip_transform_view.h
__ranges/zip_view.h
__split_buffer
__std_mbstate_t.h
@@ -780,7 +783,6 @@ set(files
__tuple/make_tuple_types.h
__tuple/sfinae_helpers.h
__tuple/tuple_element.h
- __tuple/tuple_indices.h
__tuple/tuple_like.h
__tuple/tuple_like_ext.h
__tuple/tuple_like_no_subrange.h
diff --git a/libcxx/include/__algorithm/copy.h b/libcxx/include/__algorithm/copy.h
index ea98031..6387728 100644
--- a/libcxx/include/__algorithm/copy.h
+++ b/libcxx/include/__algorithm/copy.h
@@ -182,7 +182,7 @@ struct __copy_impl {
}
};
- template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator<_InIter>::value, int> = 0>
+ template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator_v<_InIter>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
std::__for_each_segment(__first, __last, _CopySegment<_InIter, _OutIter>(__result));
@@ -192,7 +192,7 @@ struct __copy_impl {
template <class _InIter,
class _OutIter,
__enable_if_t<__has_random_access_iterator_category<_InIter>::value &&
- !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value,
+ !__is_segmented_iterator_v<_InIter> && __is_segmented_iterator_v<_OutIter>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
diff --git a/libcxx/include/__algorithm/copy_backward.h b/libcxx/include/__algorithm/copy_backward.h
index 9f89064..807c64b 100644
--- a/libcxx/include/__algorithm/copy_backward.h
+++ b/libcxx/include/__algorithm/copy_backward.h
@@ -170,7 +170,7 @@ struct __copy_backward_impl {
return std::make_pair(std::move(__original_last_iter), std::move(__result));
}
- template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator<_InIter>::value, int> = 0>
+ template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator_v<_InIter>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
using _Traits = __segmented_iterator_traits<_InIter>;
@@ -200,7 +200,7 @@ struct __copy_backward_impl {
template <class _InIter,
class _OutIter,
__enable_if_t<__has_random_access_iterator_category<_InIter>::value &&
- !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value,
+ !__is_segmented_iterator_v<_InIter> && __is_segmented_iterator_v<_OutIter>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h
index a7d9374..8c8cb58 100644
--- a/libcxx/include/__algorithm/find.h
+++ b/libcxx/include/__algorithm/find.h
@@ -149,7 +149,7 @@ struct __find_segment;
template <class _SegmentedIterator,
class _Tp,
class _Proj,
- __enable_if_t<__is_segmented_iterator<_SegmentedIterator>::value, int> = 0>
+ __enable_if_t<__is_segmented_iterator_v<_SegmentedIterator>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator
__find(_SegmentedIterator __first, _SegmentedIterator __last, const _Tp& __value, _Proj& __proj) {
return std::__find_segment_if(std::move(__first), std::move(__last), __find_segment<_Tp>(__value), __proj);
diff --git a/libcxx/include/__algorithm/for_each.h b/libcxx/include/__algorithm/for_each.h
index 4167eec..e31fcae 100644
--- a/libcxx/include/__algorithm/for_each.h
+++ b/libcxx/include/__algorithm/for_each.h
@@ -39,7 +39,7 @@ __for_each(_InputIterator __first, _Sent __last, _Func& __f, _Proj& __proj) {
template <class _SegmentedIterator,
class _Func,
class _Proj,
- __enable_if_t<__is_segmented_iterator<_SegmentedIterator>::value, int> = 0>
+ __enable_if_t<__is_segmented_iterator_v<_SegmentedIterator>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _SegmentedIterator
__for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Func& __func, _Proj& __proj) {
using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator;
diff --git a/libcxx/include/__algorithm/for_each_n.h b/libcxx/include/__algorithm/for_each_n.h
index 9a6c6bb..04650e1 100644
--- a/libcxx/include/__algorithm/for_each_n.h
+++ b/libcxx/include/__algorithm/for_each_n.h
@@ -37,8 +37,8 @@ template <class _InputIterator,
class _Func,
class _Proj,
__enable_if_t<!__has_random_access_iterator_category<_InputIterator>::value &&
- _Or< _Not<__is_segmented_iterator<_InputIterator> >,
- _Not<__has_random_access_local_iterator<_InputIterator> > >::value,
+ _Or<integral_constant<bool, !__is_segmented_iterator_v<_InputIterator> >,
+ _Not<__has_random_access_local_iterator<_InputIterator> > >::value,
int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator
__for_each_n(_InputIterator __first, _Size __orig_n, _Func& __f, _Proj& __proj) {
@@ -71,7 +71,7 @@ template <class _SegmentedIterator,
class _Func,
class _Proj,
__enable_if_t<!__has_random_access_iterator_category<_SegmentedIterator>::value &&
- __is_segmented_iterator<_SegmentedIterator>::value &&
+ __is_segmented_iterator_v<_SegmentedIterator> &&
__has_random_access_iterator_category<
typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator>::value,
int> = 0>
diff --git a/libcxx/include/__algorithm/for_each_n_segment.h b/libcxx/include/__algorithm/for_each_n_segment.h
index 1b522fb..a433df5 100644
--- a/libcxx/include/__algorithm/for_each_n_segment.h
+++ b/libcxx/include/__algorithm/for_each_n_segment.h
@@ -27,7 +27,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _SegmentedIterator, class _Size, class _Functor>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator
__for_each_n_segment(_SegmentedIterator __first, _Size __orig_n, _Functor __func) {
- static_assert(__is_segmented_iterator<_SegmentedIterator>::value &&
+ static_assert(__is_segmented_iterator_v<_SegmentedIterator> &&
__has_random_access_iterator_category<
typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator>::value,
"__for_each_n_segment only works with segmented iterators with random-access local iterators");
diff --git a/libcxx/include/__algorithm/move.h b/libcxx/include/__algorithm/move.h
index a3320e9..73b780d 100644
--- a/libcxx/include/__algorithm/move.h
+++ b/libcxx/include/__algorithm/move.h
@@ -65,7 +65,7 @@ struct __move_impl {
}
};
- template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator<_InIter>::value, int> = 0>
+ template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator_v<_InIter>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
std::__for_each_segment(__first, __last, _MoveSegment<_InIter, _OutIter>(__result));
@@ -75,7 +75,7 @@ struct __move_impl {
template <class _InIter,
class _OutIter,
__enable_if_t<__has_random_access_iterator_category<_InIter>::value &&
- !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value,
+ !__is_segmented_iterator_v<_InIter> && __is_segmented_iterator_v<_OutIter>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
diff --git a/libcxx/include/__algorithm/move_backward.h b/libcxx/include/__algorithm/move_backward.h
index 14482fe..e3e61c7b 100644
--- a/libcxx/include/__algorithm/move_backward.h
+++ b/libcxx/include/__algorithm/move_backward.h
@@ -51,7 +51,7 @@ struct __move_backward_impl {
return std::make_pair(std::move(__original_last_iter), std::move(__result));
}
- template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator<_InIter>::value, int> = 0>
+ template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator_v<_InIter>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
using _Traits = __segmented_iterator_traits<_InIter>;
@@ -81,7 +81,7 @@ struct __move_backward_impl {
template <class _InIter,
class _OutIter,
__enable_if_t<__has_random_access_iterator_category<_InIter>::value &&
- !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value,
+ !__is_segmented_iterator_v<_InIter> && __is_segmented_iterator_v<_OutIter>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
diff --git a/libcxx/include/__config b/libcxx/include/__config
index e442229..549aa06 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -38,6 +38,30 @@
# define _LIBCPP_FREESTANDING
# endif
+// NOLINTNEXTLINE(libcpp-cpp-version-check)
+# if __cplusplus < 201103L
+# define _LIBCPP_CXX03_LANG
+# endif
+
+# if __has_feature(experimental_library)
+# ifndef _LIBCPP_ENABLE_EXPERIMENTAL
+# define _LIBCPP_ENABLE_EXPERIMENTAL
+# endif
+# endif
+
+// Incomplete features get their own specific disabling flags. This makes it
+// easier to grep for target specific flags once the feature is complete.
+# if defined(_LIBCPP_ENABLE_EXPERIMENTAL) || defined(_LIBCPP_BUILDING_LIBRARY)
+# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 1
+# else
+# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 0
+# endif
+
+# define _LIBCPP_HAS_EXPERIMENTAL_PSTL _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
+# define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
+# define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
+# define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
+
// HARDENING {
// TODO: Remove in LLVM 21. We're making this an error to catch folks who might not have migrated.
@@ -147,16 +171,53 @@ _LIBCPP_HARDENING_MODE_EXTENSIVE, \
_LIBCPP_HARDENING_MODE_DEBUG
# endif
+// Hardening assertion semantics generally mirror the evaluation semantics of C++26 Contracts:
+// - `ignore` evaluates the assertion but doesn't do anything if it fails (note that it differs from the Contracts
+// `ignore` semantic which wouldn't evaluate the assertion at all);
+// - `observe` logs an error (indicating, if possible, that the error is fatal) and continues execution;
+// - `quick-enforce` terminates the program as fast as possible (via trapping);
+// - `enforce` logs an error and then terminates the program.
+//
+// Notes:
+// - Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant
+// to make adopting hardening easier but should not be used outside of this scenario;
+// - C++26 wording for Library Hardening precludes a conforming Hardened implementation from using the Contracts
+// `ignore` semantic when evaluating hardened preconditions in the Library. Libc++ allows using this semantic for
+// hardened preconditions, however, be aware that using `ignore` does not produce a conforming "Hardened"
+// implementation, unlike the other semantics above.
+// clang-format off
+# define _LIBCPP_ASSERTION_SEMANTIC_IGNORE (1 << 1)
+# define _LIBCPP_ASSERTION_SEMANTIC_OBSERVE (1 << 2)
+# define _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE (1 << 3)
+# define _LIBCPP_ASSERTION_SEMANTIC_ENFORCE (1 << 4)
+// clang-format on
+
+// Allow users to define an arbitrary assertion semantic; otherwise, use the default mapping from modes to semantics.
+// The default is for production-capable modes to use `quick-enforce` (i.e., trap) and for the `debug` mode to use
+// `enforce` (i.e., log and abort).
+# ifndef _LIBCPP_ASSERTION_SEMANTIC
+
+# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
+# else
+# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
+# endif
+
+# else
+# if !_LIBCPP_HAS_EXPERIMENTAL_LIBRARY
+# error "Assertion semantics are an experimental feature."
+# endif
+# if defined(_LIBCPP_CXX03_LANG)
+# error "Assertion semantics are not available in the C++03 mode."
+# endif
+
+# endif // _LIBCPP_ASSERTION_SEMANTIC
+
// } HARDENING
# define _LIBCPP_TOSTRING2(x) #x
# define _LIBCPP_TOSTRING(x) _LIBCPP_TOSTRING2(x)
-// NOLINTNEXTLINE(libcpp-cpp-version-check)
-# if __cplusplus < 201103L
-# define _LIBCPP_CXX03_LANG
-# endif
-
# ifndef __has_constexpr_builtin
# define __has_constexpr_builtin(x) 0
# endif
@@ -190,24 +251,6 @@ _LIBCPP_HARDENING_MODE_DEBUG
# define _LIBCPP_ABI_VCRUNTIME
# endif
-# if __has_feature(experimental_library)
-# ifndef _LIBCPP_ENABLE_EXPERIMENTAL
-# define _LIBCPP_ENABLE_EXPERIMENTAL
-# endif
-# endif
-
-// Incomplete features get their own specific disabling flags. This makes it
-// easier to grep for target specific flags once the feature is complete.
-# if defined(_LIBCPP_ENABLE_EXPERIMENTAL) || defined(_LIBCPP_BUILDING_LIBRARY)
-# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 1
-# else
-# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 0
-# endif
-
-# define _LIBCPP_HAS_EXPERIMENTAL_PSTL _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
-# define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
-# define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
-
# if defined(__MVS__)
# include <features.h> // for __NATIVE_ASCII_F
# endif
@@ -1081,6 +1124,20 @@ typedef __char32_t char32_t;
# define _LIBCPP_DIAGNOSE_WARNING(...)
# endif
+# if __has_attribute(__diagnose_if__) && !defined(_LIBCPP_APPLE_CLANG_VER) && \
+ (!defined(_LIBCPP_CLANG_VER) || _LIBCPP_CLANG_VER >= 2001)
+# define _LIBCPP_DIAGNOSE_IF(...) __attribute__((__diagnose_if__(__VA_ARGS__)))
+# else
+# define _LIBCPP_DIAGNOSE_IF(...)
+# endif
+
+# define _LIBCPP_DIAGNOSE_NULLPTR_IF(condition, condition_description) \
+ _LIBCPP_DIAGNOSE_IF( \
+ condition, \
+ "null passed to callee that requires a non-null argument" condition_description, \
+ "warning", \
+ "nonnull")
+
# if __has_cpp_attribute(_Clang::__lifetimebound__)
# define _LIBCPP_LIFETIMEBOUND [[_Clang::__lifetimebound__]]
# else
diff --git a/libcxx/include/__cxx03/__config b/libcxx/include/__cxx03/__config
index ef47327..9b88a49 100644
--- a/libcxx/include/__cxx03/__config
+++ b/libcxx/include/__cxx03/__config
@@ -152,6 +152,10 @@ _LIBCPP_HARDENING_MODE_EXTENSIVE, \
_LIBCPP_HARDENING_MODE_DEBUG
# endif
+# ifdef _LIBCPP_ASSERTION_SEMANTIC
+# error "Assertion semantics are not available in the C++03 mode."
+# endif
+
// } HARDENING
# define _LIBCPP_TOSTRING2(x) #x
diff --git a/libcxx/include/__flat_map/flat_multimap.h b/libcxx/include/__flat_map/flat_multimap.h
index 0af6aac..260d93e 100644
--- a/libcxx/include/__flat_map/flat_multimap.h
+++ b/libcxx/include/__flat_map/flat_multimap.h
@@ -114,11 +114,12 @@ public:
class value_compare {
private:
_LIBCPP_NO_UNIQUE_ADDRESS key_compare __comp_;
- _LIBCPP_HIDE_FROM_ABI value_compare(key_compare __c) : __comp_(__c) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 value_compare(key_compare __c) : __comp_(__c) {}
friend flat_multimap;
public:
- _LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
+ operator()(const_reference __x, const_reference __y) const {
return __comp_(__x.first, __y.first);
}
};
@@ -137,17 +138,17 @@ private:
public:
// [flat.map.cons], construct/copy/destroy
- _LIBCPP_HIDE_FROM_ABI flat_multimap() noexcept(
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap() noexcept(
is_nothrow_default_constructible_v<_KeyContainer> && is_nothrow_default_constructible_v<_MappedContainer> &&
is_nothrow_default_constructible_v<_Compare>)
: __containers_(), __compare_() {}
- _LIBCPP_HIDE_FROM_ABI flat_multimap(const flat_multimap&) = default;
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(const flat_multimap&) = default;
// The copy/move constructors are not specified in the spec, which means they should be defaulted.
// However, the move constructor can potentially leave a moved-from object in an inconsistent
// state if an exception is thrown.
- _LIBCPP_HIDE_FROM_ABI flat_multimap(flat_multimap&& __other) noexcept(
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(flat_multimap&& __other) noexcept(
is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_MappedContainer> &&
is_nothrow_move_constructible_v<_Compare>)
# if _LIBCPP_HAS_EXCEPTIONS
@@ -168,7 +169,8 @@ public:
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(const flat_multimap& __other, const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+ flat_multimap(const flat_multimap& __other, const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_tag{},
__alloc,
__other.__containers_.keys,
@@ -177,7 +179,7 @@ public:
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(flat_multimap&& __other, const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(flat_multimap&& __other, const _Allocator& __alloc)
# if _LIBCPP_HAS_EXCEPTIONS
try
# endif // _LIBCPP_HAS_EXCEPTIONS
@@ -194,7 +196,7 @@ public:
# endif // _LIBCPP_HAS_EXCEPTIONS
}
- _LIBCPP_HIDE_FROM_ABI flat_multimap(
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(
key_container_type __key_cont, mapped_container_type __mapped_cont, const key_compare& __comp = key_compare())
: __containers_{.keys = std::move(__key_cont), .values = std::move(__mapped_cont)}, __compare_(__comp) {
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__containers_.keys.size() == __containers_.values.size(),
@@ -204,7 +206,7 @@ public:
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(
const key_container_type& __key_cont, const mapped_container_type& __mapped_cont, const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_tag{}, __alloc, __key_cont, __mapped_cont) {
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__containers_.keys.size() == __containers_.values.size(),
@@ -214,22 +216,22 @@ public:
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI
- flat_multimap(const key_container_type& __key_cont,
- const mapped_container_type& __mapped_cont,
- const key_compare& __comp,
- const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(
+ const key_container_type& __key_cont,
+ const mapped_container_type& __mapped_cont,
+ const key_compare& __comp,
+ const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_tag{}, __alloc, __key_cont, __mapped_cont, __comp) {
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__containers_.keys.size() == __containers_.values.size(),
"flat_multimap keys and mapped containers have different size");
__sort();
}
- _LIBCPP_HIDE_FROM_ABI
- flat_multimap(sorted_equivalent_t,
- key_container_type __key_cont,
- mapped_container_type __mapped_cont,
- const key_compare& __comp = key_compare())
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(
+ sorted_equivalent_t,
+ key_container_type __key_cont,
+ mapped_container_type __mapped_cont,
+ const key_compare& __comp = key_compare())
: __containers_{.keys = std::move(__key_cont), .values = std::move(__mapped_cont)}, __compare_(__comp) {
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__containers_.keys.size() == __containers_.values.size(),
"flat_multimap keys and mapped containers have different size");
@@ -238,11 +240,11 @@ public:
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI
- flat_multimap(sorted_equivalent_t,
- const key_container_type& __key_cont,
- const mapped_container_type& __mapped_cont,
- const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(
+ sorted_equivalent_t,
+ const key_container_type& __key_cont,
+ const mapped_container_type& __mapped_cont,
+ const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_tag{}, __alloc, __key_cont, __mapped_cont) {
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__containers_.keys.size() == __containers_.values.size(),
"flat_multimap keys and mapped containers have different size");
@@ -251,33 +253,35 @@ public:
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI
- flat_multimap(sorted_equivalent_t,
- const key_container_type& __key_cont,
- const mapped_container_type& __mapped_cont,
- const key_compare& __comp,
- const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(
+ sorted_equivalent_t,
+ const key_container_type& __key_cont,
+ const mapped_container_type& __mapped_cont,
+ const key_compare& __comp,
+ const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_tag{}, __alloc, __key_cont, __mapped_cont, __comp) {
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__containers_.keys.size() == __containers_.values.size(),
"flat_multimap keys and mapped containers have different size");
_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__is_sorted(__containers_.keys), "Key container is not sorted");
}
- _LIBCPP_HIDE_FROM_ABI explicit flat_multimap(const key_compare& __comp) : __containers_(), __compare_(__comp) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit flat_multimap(const key_compare& __comp)
+ : __containers_(), __compare_(__comp) {}
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(const key_compare& __comp, const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+ flat_multimap(const key_compare& __comp, const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {}
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI explicit flat_multimap(const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit flat_multimap(const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_empty_tag{}, __alloc) {}
template <class _InputIterator>
requires __has_input_iterator_category<_InputIterator>::value
- _LIBCPP_HIDE_FROM_ABI
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
flat_multimap(_InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare())
: __containers_(), __compare_(__comp) {
insert(__first, __last);
@@ -285,7 +289,7 @@ public:
template <class _InputIterator, class _Allocator>
requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>)
- _LIBCPP_HIDE_FROM_ABI
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
flat_multimap(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {
insert(__first, __last);
@@ -293,91 +297,99 @@ public:
template <class _InputIterator, class _Allocator>
requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>)
- _LIBCPP_HIDE_FROM_ABI flat_multimap(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+ flat_multimap(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_empty_tag{}, __alloc) {
insert(__first, __last);
}
template <_ContainerCompatibleRange<value_type> _Range>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(from_range_t __fr, _Range&& __rg)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(from_range_t __fr, _Range&& __rg)
: flat_multimap(__fr, std::forward<_Range>(__rg), key_compare()) {}
template <_ContainerCompatibleRange<value_type> _Range, class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(from_range_t, _Range&& __rg, const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+ flat_multimap(from_range_t, _Range&& __rg, const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_empty_tag{}, __alloc) {
insert_range(std::forward<_Range>(__rg));
}
template <_ContainerCompatibleRange<value_type> _Range>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(from_range_t, _Range&& __rg, const key_compare& __comp) : flat_multimap(__comp) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+ flat_multimap(from_range_t, _Range&& __rg, const key_compare& __comp)
+ : flat_multimap(__comp) {
insert_range(std::forward<_Range>(__rg));
}
template <_ContainerCompatibleRange<value_type> _Range, class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+ flat_multimap(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {
insert_range(std::forward<_Range>(__rg));
}
template <class _InputIterator>
requires __has_input_iterator_category<_InputIterator>::value
- _LIBCPP_HIDE_FROM_ABI flat_multimap(
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(
sorted_equivalent_t, _InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare())
: __containers_(), __compare_(__comp) {
insert(sorted_equivalent, __first, __last);
}
template <class _InputIterator, class _Allocator>
requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>)
- _LIBCPP_HIDE_FROM_ABI
- flat_multimap(sorted_equivalent_t,
- _InputIterator __first,
- _InputIterator __last,
- const key_compare& __comp,
- const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(
+ sorted_equivalent_t,
+ _InputIterator __first,
+ _InputIterator __last,
+ const key_compare& __comp,
+ const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {
insert(sorted_equivalent, __first, __last);
}
template <class _InputIterator, class _Allocator>
requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>)
- _LIBCPP_HIDE_FROM_ABI
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
flat_multimap(sorted_equivalent_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc)
: flat_multimap(__ctor_uses_allocator_empty_tag{}, __alloc) {
insert(sorted_equivalent, __first, __last);
}
- _LIBCPP_HIDE_FROM_ABI flat_multimap(initializer_list<value_type> __il, const key_compare& __comp = key_compare())
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+ flat_multimap(initializer_list<value_type> __il, const key_compare& __comp = key_compare())
: flat_multimap(__il.begin(), __il.end(), __comp) {}
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
flat_multimap(initializer_list<value_type> __il, const key_compare& __comp, const _Allocator& __alloc)
: flat_multimap(__il.begin(), __il.end(), __comp, __alloc) {}
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(initializer_list<value_type> __il, const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+ flat_multimap(initializer_list<value_type> __il, const _Allocator& __alloc)
: flat_multimap(__il.begin(), __il.end(), __alloc) {}
- _LIBCPP_HIDE_FROM_ABI
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
flat_multimap(sorted_equivalent_t, initializer_list<value_type> __il, const key_compare& __comp = key_compare())
: flat_multimap(sorted_equivalent, __il.begin(), __il.end(), __comp) {}
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(
sorted_equivalent_t, initializer_list<value_type> __il, const key_compare& __comp, const _Allocator& __alloc)
: flat_multimap(sorted_equivalent, __il.begin(), __il.end(), __comp, __alloc) {}
template <class _Allocator>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(sorted_equivalent_t, initializer_list<value_type> __il, const _Allocator& __alloc)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+ flat_multimap(sorted_equivalent_t, initializer_list<value_type> __il, const _Allocator& __alloc)
: flat_multimap(sorted_equivalent, __il.begin(), __il.end(), __alloc) {}
- _LIBCPP_HIDE_FROM_ABI flat_multimap& operator=(initializer_list<value_type> __il) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap& operator=(initializer_list<value_type> __il) {
clear();
insert(__il);
return *this;
@@ -386,9 +398,9 @@ public:
// copy/move assignment are not specified in the spec (defaulted)
// but move assignment can potentially leave moved from object in an inconsistent
// state if an exception is thrown
- _LIBCPP_HIDE_FROM_ABI flat_multimap& operator=(const flat_multimap&) = default;
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap& operator=(const flat_multimap&) = default;
- _LIBCPP_HIDE_FROM_ABI flat_multimap& operator=(flat_multimap&& __other) noexcept(
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap& operator=(flat_multimap&& __other) noexcept(
is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_MappedContainer> &&
is_nothrow_move_assignable_v<_Compare>) {
auto __clear_other_guard = std::__make_scope_guard([&]() noexcept { __other.clear() /* noexcept */; });
@@ -400,38 +412,54 @@ public:
}
// iterators
- _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator begin() noexcept {
return iterator(__containers_.keys.begin(), __containers_.values.begin());
}
- _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator begin() const noexcept {
return const_iterator(__containers_.keys.begin(), __containers_.values.begin());
}
- _LIBCPP_HIDE_FROM_ABI iterator end() noexcept {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator end() noexcept {
return iterator(__containers_.keys.end(), __containers_.values.end());
}
- _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator end() const noexcept {
return const_iterator(__containers_.keys.end(), __containers_.values.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 _LIBCPP_CONSTEXPR_SINCE_CXX26 reverse_iterator rbegin() noexcept {
+ return reverse_iterator(end());
+ }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator rbegin() const noexcept {
+ return const_reverse_iterator(end());
+ }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 reverse_iterator rend() noexcept {
+ return reverse_iterator(begin());
+ }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 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()); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cbegin() const noexcept { return begin(); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cend() const noexcept { return end(); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator crbegin() const noexcept {
+ return const_reverse_iterator(end());
+ }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator crend() const noexcept {
+ return const_reverse_iterator(begin());
+ }
// [flat.map.capacity], capacity
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __containers_.keys.empty(); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool empty() const noexcept {
+ return __containers_.keys.empty();
+ }
- _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __containers_.keys.size(); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type size() const noexcept {
+ return __containers_.keys.size();
+ }
- _LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type max_size() const noexcept {
return std::min<size_type>(__containers_.keys.max_size(), __containers_.values.max_size());
}
@@ -439,7 +467,7 @@ public:
template <class... _Args>
requires is_constructible_v<pair<key_type, mapped_type>, _Args...> && is_move_constructible_v<key_type> &&
is_move_constructible_v<mapped_type>
- _LIBCPP_HIDE_FROM_ABI iterator emplace(_Args&&... __args) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator emplace(_Args&&... __args) {
std::pair<key_type, mapped_type> __pair(std::forward<_Args>(__args)...);
auto __key_it = std::upper_bound(__containers_.keys.begin(), __containers_.keys.end(), __pair.first, __compare_);
auto __mapped_it = __corresponding_mapped_it(*this, __key_it);
@@ -450,7 +478,7 @@ public:
template <class... _Args>
requires is_constructible_v<pair<key_type, mapped_type>, _Args...>
- _LIBCPP_HIDE_FROM_ABI iterator emplace_hint(const_iterator __hint, _Args&&... __args) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator emplace_hint(const_iterator __hint, _Args&&... __args) {
std::pair<key_type, mapped_type> __pair(std::forward<_Args>(__args)...);
auto __prev_larger = __hint != cbegin() && __compare_(__pair.first, (__hint - 1)->first);
@@ -490,33 +518,35 @@ public:
*this, __key_iter, __mapped_iter, std::move(__pair.first), std::move(__pair.second));
}
- _LIBCPP_HIDE_FROM_ABI iterator insert(const value_type& __x) { return emplace(__x); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator insert(const value_type& __x) { return emplace(__x); }
- _LIBCPP_HIDE_FROM_ABI iterator insert(value_type&& __x) { return emplace(std::move(__x)); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator insert(value_type&& __x) {
+ return emplace(std::move(__x));
+ }
- _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, const value_type& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 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) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator insert(const_iterator __hint, value_type&& __x) {
return emplace_hint(__hint, std::move(__x));
}
template <class _PairLike>
requires is_constructible_v<pair<key_type, mapped_type>, _PairLike>
- _LIBCPP_HIDE_FROM_ABI iterator insert(_PairLike&& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator insert(_PairLike&& __x) {
return emplace(std::forward<_PairLike>(__x));
}
template <class _PairLike>
requires is_constructible_v<pair<key_type, mapped_type>, _PairLike>
- _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _PairLike&& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator insert(const_iterator __hint, _PairLike&& __x) {
return emplace_hint(__hint, std::forward<_PairLike>(__x));
}
template <class _InputIterator>
requires __has_input_iterator_category<_InputIterator>::value
- _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(_InputIterator __first, _InputIterator __last) {
if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) {
__reserve(__last - __first);
}
@@ -525,7 +555,8 @@ public:
template <class _InputIterator>
requires __has_input_iterator_category<_InputIterator>::value
- _LIBCPP_HIDE_FROM_ABI void insert(sorted_equivalent_t, _InputIterator __first, _InputIterator __last) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+ insert(sorted_equivalent_t, _InputIterator __first, _InputIterator __last) {
if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) {
__reserve(__last - __first);
}
@@ -534,7 +565,7 @@ public:
}
template <_ContainerCompatibleRange<value_type> _Range>
- _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(_Range&& __range) {
if constexpr (ranges::sized_range<_Range>) {
__reserve(ranges::size(__range));
}
@@ -542,19 +573,23 @@ public:
__append_sort_merge</*WasSorted = */ false>(ranges::begin(__range), ranges::end(__range));
}
- _LIBCPP_HIDE_FROM_ABI void insert(initializer_list<value_type> __il) { insert(__il.begin(), __il.end()); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) {
+ insert(__il.begin(), __il.end());
+ }
- _LIBCPP_HIDE_FROM_ABI void insert(sorted_equivalent_t, initializer_list<value_type> __il) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+ insert(sorted_equivalent_t, initializer_list<value_type> __il) {
insert(sorted_equivalent, __il.begin(), __il.end());
}
- _LIBCPP_HIDE_FROM_ABI containers extract() && {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 containers extract() && {
auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; });
auto __ret = std::move(__containers_);
return __ret;
}
- _LIBCPP_HIDE_FROM_ABI void replace(key_container_type&& __key_cont, mapped_container_type&& __mapped_cont) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+ replace(key_container_type&& __key_cont, mapped_container_type&& __mapped_cont) {
_LIBCPP_ASSERT_VALID_INPUT_RANGE(
__key_cont.size() == __mapped_cont.size(), "flat_multimap keys and mapped containers have different size");
@@ -565,15 +600,15 @@ public:
__guard.__complete();
}
- _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __position) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator erase(iterator __position) {
return __erase(__position.__key_iter_, __position.__mapped_iter_);
}
- _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __position) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator erase(const_iterator __position) {
return __erase(__position.__key_iter_, __position.__mapped_iter_);
}
- _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type erase(const key_type& __x) {
auto [__first, __last] = equal_range(__x);
auto __res = __last - __first;
erase(__first, __last);
@@ -583,14 +618,14 @@ public:
template <class _Kp>
requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> &&
!is_convertible_v<_Kp &&, const_iterator>)
- _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 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) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator erase(const_iterator __first, const_iterator __last) {
auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; });
auto __key_it = __containers_.keys.erase(__first.__key_iter_, __last.__key_iter_);
auto __mapped_it = __containers_.values.erase(__first.__mapped_iter_, __last.__mapped_iter_);
@@ -598,7 +633,7 @@ public:
return iterator(std::move(__key_it), std::move(__mapped_it));
}
- _LIBCPP_HIDE_FROM_ABI void swap(flat_multimap& __y) noexcept {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_multimap& __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
@@ -607,137 +642,160 @@ public:
ranges::swap(__containers_.values, __y.__containers_.values);
}
- _LIBCPP_HIDE_FROM_ABI void clear() noexcept {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept {
__containers_.keys.clear();
__containers_.values.clear();
}
// observers
- _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __compare_; }
- _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return value_compare(__compare_); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 key_compare key_comp() const { return __compare_; }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 value_compare value_comp() const {
+ return value_compare(__compare_);
+ }
- _LIBCPP_HIDE_FROM_ABI const key_container_type& keys() const noexcept { return __containers_.keys; }
- _LIBCPP_HIDE_FROM_ABI const mapped_container_type& values() const noexcept { return __containers_.values; }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const key_container_type& keys() const noexcept {
+ return __containers_.keys;
+ }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const mapped_container_type& values() const noexcept {
+ return __containers_.values;
+ }
// map operations
- _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __x) { return __find_impl(*this, __x); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 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); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator find(const key_type& __x) const {
+ return __find_impl(*this, __x);
+ }
template <class _Kp>
requires __is_compare_transparent
- _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator find(const _Kp& __x) {
return __find_impl(*this, __x);
}
template <class _Kp>
requires __is_compare_transparent
- _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator find(const _Kp& __x) const {
return __find_impl(*this, __x);
}
- _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const key_type& __x) const {
auto [__first, __last] = equal_range(__x);
return __last - __first;
}
template <class _Kp>
requires __is_compare_transparent
- _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const _Kp& __x) const {
auto [__first, __last] = equal_range(__x);
return __last - __first;
}
- _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const key_type& __x) const {
+ return find(__x) != end();
+ }
template <class _Kp>
requires __is_compare_transparent
- _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const _Kp& __x) const {
return find(__x) != end();
}
- _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __x) { return __lower_bound<iterator>(*this, __x); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const key_type& __x) {
+ return __lower_bound<iterator>(*this, __x);
+ }
- _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator lower_bound(const key_type& __x) const {
return __lower_bound<const_iterator>(*this, __x);
}
template <class _Kp>
requires __is_compare_transparent
- _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const _Kp& __x) {
return __lower_bound<iterator>(*this, __x);
}
template <class _Kp>
requires __is_compare_transparent
- _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator lower_bound(const _Kp& __x) const {
return __lower_bound<const_iterator>(*this, __x);
}
- _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) { return __upper_bound<iterator>(*this, __x); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const key_type& __x) {
+ return __upper_bound<iterator>(*this, __x);
+ }
- _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator upper_bound(const key_type& __x) const {
return __upper_bound<const_iterator>(*this, __x);
}
template <class _Kp>
requires __is_compare_transparent
- _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const _Kp& __x) {
return __upper_bound<iterator>(*this, __x);
}
template <class _Kp>
requires __is_compare_transparent
- _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator upper_bound(const _Kp& __x) const {
return __upper_bound<const_iterator>(*this, __x);
}
- _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<iterator, iterator> equal_range(const key_type& __x) {
return __equal_range_impl(*this, __x);
}
- _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __x) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<const_iterator, const_iterator>
+ equal_range(const key_type& __x) const {
return __equal_range_impl(*this, __x);
}
template <class _Kp>
requires __is_compare_transparent
- _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _Kp& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<iterator, iterator> equal_range(const _Kp& __x) {
return __equal_range_impl(*this, __x);
}
template <class _Kp>
requires __is_compare_transparent
- _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _Kp& __x) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<const_iterator, const_iterator>
+ equal_range(const _Kp& __x) const {
return __equal_range_impl(*this, __x);
}
- friend _LIBCPP_HIDE_FROM_ABI bool operator==(const flat_multimap& __x, const flat_multimap& __y) {
+ friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
+ operator==(const flat_multimap& __x, const flat_multimap& __y) {
return ranges::equal(__x, __y);
}
- friend _LIBCPP_HIDE_FROM_ABI auto operator<=>(const flat_multimap& __x, const flat_multimap& __y) {
+ friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 auto
+ operator<=>(const flat_multimap& __x, const flat_multimap& __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_multimap& __x, flat_multimap& __y) noexcept { __x.swap(__y); }
+ friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+ swap(flat_multimap& __x, flat_multimap& __y) noexcept {
+ __x.swap(__y);
+ }
private:
struct __ctor_uses_allocator_tag {
- explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_tag() = default;
+ explicit _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __ctor_uses_allocator_tag() = default;
};
struct __ctor_uses_allocator_empty_tag {
- explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_empty_tag() = default;
+ explicit _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __ctor_uses_allocator_empty_tag() = default;
};
template <class _Allocator, class _KeyCont, class _MappedCont, class... _CompArg>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI
- flat_multimap(__ctor_uses_allocator_tag,
- const _Allocator& __alloc,
- _KeyCont&& __key_cont,
- _MappedCont&& __mapped_cont,
- _CompArg&&... __comp)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multimap(
+ __ctor_uses_allocator_tag,
+ const _Allocator& __alloc,
+ _KeyCont&& __key_cont,
+ _MappedCont&& __mapped_cont,
+ _CompArg&&... __comp)
: __containers_{.keys = std::make_obj_using_allocator<key_container_type>(
__alloc, std::forward<_KeyCont>(__key_cont)),
.values = std::make_obj_using_allocator<mapped_container_type>(
@@ -746,29 +804,32 @@ private:
template <class _Allocator, class... _CompArg>
requires __allocator_ctor_constraint<_Allocator>
- _LIBCPP_HIDE_FROM_ABI flat_multimap(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+ flat_multimap(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp)
: __containers_{.keys = std::make_obj_using_allocator<key_container_type>(__alloc),
.values = std::make_obj_using_allocator<mapped_container_type>(__alloc)},
__compare_(std::forward<_CompArg>(__comp)...) {}
- _LIBCPP_HIDE_FROM_ABI bool __is_sorted(auto&& __key_container) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool __is_sorted(auto&& __key_container) const {
return ranges::is_sorted(__key_container, __compare_);
}
- _LIBCPP_HIDE_FROM_ABI void __sort() {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __sort() {
auto __zv = ranges::views::zip(__containers_.keys, __containers_.values);
ranges::sort(__zv, __compare_, [](const auto& __p) -> decltype(auto) { return std::get<0>(__p); });
}
template <class _Self, class _KeyIter>
- _LIBCPP_HIDE_FROM_ABI static auto __corresponding_mapped_it(_Self&& __self, _KeyIter&& __key_iter) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static auto
+ __corresponding_mapped_it(_Self&& __self, _KeyIter&& __key_iter) {
return __self.__containers_.values.begin() +
static_cast<ranges::range_difference_t<mapped_container_type>>(
ranges::distance(__self.__containers_.keys.begin(), __key_iter));
}
template <bool _WasSorted, class _InputIterator, class _Sentinel>
- _LIBCPP_HIDE_FROM_ABI void __append_sort_merge(_InputIterator __first, _Sentinel __last) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+ __append_sort_merge(_InputIterator __first, _Sentinel __last) {
auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; });
size_t __num_appended = __flat_map_utils::__append(*this, std::move(__first), std::move(__last));
if (__num_appended != 0) {
@@ -791,7 +852,7 @@ private:
}
template <class _Self, class _Kp>
- _LIBCPP_HIDE_FROM_ABI static auto __find_impl(_Self&& __self, const _Kp& __key) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 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->first)) {
@@ -801,7 +862,7 @@ private:
}
template <class _Self, class _Kp>
- _LIBCPP_HIDE_FROM_ABI static auto __equal_range_impl(_Self&& __self, const _Kp& __key) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static auto __equal_range_impl(_Self&& __self, const _Kp& __key) {
auto [__key_first, __key_last] =
std::equal_range(__self.__containers_.keys.begin(), __self.__containers_.keys.end(), __key, __self.__compare_);
@@ -811,7 +872,7 @@ private:
}
template <class _Res, class _Self, class _Kp>
- _LIBCPP_HIDE_FROM_ABI static _Res __lower_bound(_Self&& __self, _Kp& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static _Res __lower_bound(_Self&& __self, _Kp& __x) {
auto __key_iter =
std::lower_bound(__self.__containers_.keys.begin(), __self.__containers_.keys.end(), __x, __self.__compare_);
auto __mapped_iter = __corresponding_mapped_it(__self, __key_iter);
@@ -819,14 +880,14 @@ private:
}
template <class _Res, class _Self, class _Kp>
- _LIBCPP_HIDE_FROM_ABI static _Res __upper_bound(_Self&& __self, _Kp& __x) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static _Res __upper_bound(_Self&& __self, _Kp& __x) {
auto __key_iter =
std::upper_bound(__self.__containers_.keys.begin(), __self.__containers_.keys.end(), __x, __self.__compare_);
auto __mapped_iter = __corresponding_mapped_it(__self, __key_iter);
return _Res(std::move(__key_iter), std::move(__mapped_iter));
}
- _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __size) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __reserve(size_t __size) {
if constexpr (__container_traits<_KeyContainer>::__reservable) {
__containers_.keys.reserve(__size);
}
@@ -837,7 +898,8 @@ private:
}
template <class _KIter, class _MIter>
- _LIBCPP_HIDE_FROM_ABI iterator __erase(_KIter __key_iter_to_remove, _MIter __mapped_iter_to_remove) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator
+ __erase(_KIter __key_iter_to_remove, _MIter __mapped_iter_to_remove) {
auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; });
auto __key_iter = __containers_.keys.erase(__key_iter_to_remove);
auto __mapped_iter = __containers_.values.erase(__mapped_iter_to_remove);
@@ -847,7 +909,8 @@ private:
template <class _Key2, class _Tp2, class _Compare2, class _KeyContainer2, class _MappedContainer2, class _Predicate>
friend typename flat_multimap<_Key2, _Tp2, _Compare2, _KeyContainer2, _MappedContainer2>::size_type
- erase_if(flat_multimap<_Key2, _Tp2, _Compare2, _KeyContainer2, _MappedContainer2>&, _Predicate);
+ _LIBCPP_CONSTEXPR_SINCE_CXX26
+ erase_if(flat_multimap<_Key2, _Tp2, _Compare2, _KeyContainer2, _MappedContainer2>&, _Predicate);
friend __flat_map_utils;
@@ -855,8 +918,9 @@ private:
_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 {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_equiv(key_compare __c) : __comp_(__c) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
+ operator()(const_reference __x, const_reference __y) const {
return !__comp_(std::get<0>(__x), std::get<0>(__y)) && !__comp_(std::get<0>(__y), std::get<0>(__x));
}
key_compare __comp_;
@@ -980,8 +1044,9 @@ struct uses_allocator<flat_multimap<_Key, _Tp, _Compare, _KeyContainer, _MappedC
: bool_constant<uses_allocator_v<_KeyContainer, _Allocator> && uses_allocator_v<_MappedContainer, _Allocator>> {};
template <class _Key, class _Tp, class _Compare, class _KeyContainer, class _MappedContainer, class _Predicate>
-_LIBCPP_HIDE_FROM_ABI typename flat_multimap<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>::size_type
-erase_if(flat_multimap<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>& __flat_multimap, _Predicate __pred) {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+ typename flat_multimap<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>::size_type
+ erase_if(flat_multimap<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>& __flat_multimap, _Predicate __pred) {
auto __zv = ranges::views::zip(__flat_multimap.__containers_.keys, __flat_multimap.__containers_.values);
auto __first = __zv.begin();
auto __last = __zv.end();
diff --git a/libcxx/include/__format/concepts.h b/libcxx/include/__format/concepts.h
index 28297c6..5b60370 100644
--- a/libcxx/include/__format/concepts.h
+++ b/libcxx/include/__format/concepts.h
@@ -15,12 +15,8 @@
#include <__config>
#include <__format/format_parse_context.h>
#include <__fwd/format.h>
-#include <__fwd/tuple.h>
-#include <__tuple/tuple_size.h>
-#include <__type_traits/is_specialization.h>
#include <__type_traits/remove_const.h>
#include <__type_traits/remove_reference.h>
-#include <__utility/pair.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -65,16 +61,6 @@ concept __formattable =
# if _LIBCPP_STD_VER >= 23
template <class _Tp, class _CharT>
concept formattable = __formattable<_Tp, _CharT>;
-
-// [tuple.like] defines a tuple-like exposition only concept. This concept is
-// not related to that. Therefore it uses a different name for the concept.
-//
-// TODO FMT Add a test to validate we fail when using that concept after P2165
-// has been implemented.
-template <class _Tp>
-concept __fmt_pair_like =
- __is_specialization_v<_Tp, pair> || (__is_specialization_v<_Tp, tuple> && tuple_size_v<_Tp> == 2);
-
# endif // _LIBCPP_STD_VER >= 23
#endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__format/fmt_pair_like.h b/libcxx/include/__format/fmt_pair_like.h
new file mode 100644
index 0000000..d2f2f54
--- /dev/null
+++ b/libcxx/include/__format/fmt_pair_like.h
@@ -0,0 +1,42 @@
+// -*- 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___FORMAT_FMT_PAIR_LIKE_H
+#define _LIBCPP___FORMAT_FMT_PAIR_LIKE_H
+
+#include <__config>
+#include <__fwd/pair.h>
+#include <__fwd/tuple.h>
+#include <__tuple/tuple_size.h>
+#include <__type_traits/is_specialization.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+// [tuple.like] defines a tuple-like exposition only concept. This concept is not related to that. Therefore it uses a
+// different name for the concept.
+//
+// TODO FMT Add a test to validate we fail when using that concept after P2165 has been implemented.
+
+// [format.range.fmtkind]/2.2.1 and [tab:formatter.range.type]:
+// "U is either a specialization of pair or a specialization of tuple such that tuple_size_v<U> is 2."
+template <class _Tp>
+concept __fmt_pair_like =
+ __is_specialization_v<_Tp, pair> || (__is_specialization_v<_Tp, tuple> && tuple_size_v<_Tp> == 2);
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___FORMAT_FMT_PAIR_LIKE_H
diff --git a/libcxx/include/__format/range_default_formatter.h b/libcxx/include/__format/range_default_formatter.h
index 2769647..2d21906 100644
--- a/libcxx/include/__format/range_default_formatter.h
+++ b/libcxx/include/__format/range_default_formatter.h
@@ -18,6 +18,7 @@
#include <__chrono/statically_widen.h>
#include <__config>
#include <__format/concepts.h>
+#include <__format/fmt_pair_like.h>
#include <__format/formatter.h>
#include <__format/range_format.h>
#include <__format/range_formatter.h>
diff --git a/libcxx/include/__format/range_format.h b/libcxx/include/__format/range_format.h
index 139cfd9..fe43923 100644
--- a/libcxx/include/__format/range_format.h
+++ b/libcxx/include/__format/range_format.h
@@ -16,7 +16,7 @@
#include <__concepts/same_as.h>
#include <__config>
-#include <__format/concepts.h>
+#include <__format/fmt_pair_like.h>
#include <__ranges/concepts.h>
#include <__type_traits/remove_cvref.h>
diff --git a/libcxx/include/__format/range_formatter.h b/libcxx/include/__format/range_formatter.h
index 0d7fe99..06d2b4c 100644
--- a/libcxx/include/__format/range_formatter.h
+++ b/libcxx/include/__format/range_formatter.h
@@ -20,6 +20,7 @@
#include <__config>
#include <__format/buffer.h>
#include <__format/concepts.h>
+#include <__format/fmt_pair_like.h>
#include <__format/format_context.h>
#include <__format/format_error.h>
#include <__format/formatter.h>
diff --git a/libcxx/include/__functional/bind.h b/libcxx/include/__functional/bind.h
index 596cce0..def9e4c 100644
--- a/libcxx/include/__functional/bind.h
+++ b/libcxx/include/__functional/bind.h
@@ -83,15 +83,14 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& __mu(reference_w
template <class _Ti, class... _Uj, size_t... _Indx>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __invoke_result_t<_Ti&, _Uj...>
-__mu_expand(_Ti& __ti, tuple<_Uj...>& __uj, __tuple_indices<_Indx...>) {
+__mu_expand(_Ti& __ti, tuple<_Uj...>& __uj, __index_sequence<_Indx...>) {
return __ti(std::forward<_Uj>(std::get<_Indx>(__uj))...);
}
template <class _Ti, class... _Uj, __enable_if_t<is_bind_expression<_Ti>::value, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __invoke_result_t<_Ti&, _Uj...>
__mu(_Ti& __ti, tuple<_Uj...>& __uj) {
- typedef typename __make_tuple_indices<sizeof...(_Uj)>::type __indices;
- return std::__mu_expand(__ti, __uj, __indices());
+ return std::__mu_expand(__ti, __uj, __make_index_sequence<sizeof...(_Uj)>());
}
template <bool _IsPh, class _Ti, class _Uj>
@@ -191,7 +190,7 @@ struct __bind_return<_Fp, const tuple<_BoundArgs...>, _TupleUj, true> {
template <class _Fp, class _BoundArgs, size_t... _Indx, class _Args>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __bind_return<_Fp, _BoundArgs, _Args>::type
-__apply_functor(_Fp& __f, _BoundArgs& __bound_args, __tuple_indices<_Indx...>, _Args&& __args) {
+__apply_functor(_Fp& __f, _BoundArgs& __bound_args, __index_sequence<_Indx...>, _Args&& __args) {
return std::__invoke(__f, std::__mu(std::get<_Indx>(__bound_args), __args)...);
}
@@ -205,8 +204,6 @@ private:
_Fd __f_;
_Td __bound_args_;
- typedef typename __make_tuple_indices<sizeof...(_BoundArgs)>::type __indices;
-
public:
template <
class _Gp,
@@ -219,14 +216,22 @@ public:
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __bind_return<_Fd, _Td, tuple<_Args&&...> >::type
operator()(_Args&&... __args) {
- return std::__apply_functor(__f_, __bound_args_, __indices(), tuple<_Args&&...>(std::forward<_Args>(__args)...));
+ return std::__apply_functor(
+ __f_,
+ __bound_args_,
+ __make_index_sequence<sizeof...(_BoundArgs)>(),
+ tuple<_Args&&...>(std::forward<_Args>(__args)...));
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
typename __bind_return<const _Fd, const _Td, tuple<_Args&&...> >::type
operator()(_Args&&... __args) const {
- return std::__apply_functor(__f_, __bound_args_, __indices(), tuple<_Args&&...>(std::forward<_Args>(__args)...));
+ return std::__apply_functor(
+ __f_,
+ __bound_args_,
+ __make_index_sequence<sizeof...(_BoundArgs)>(),
+ tuple<_Args&&...>(std::forward<_Args>(__args)...));
}
};
diff --git a/libcxx/include/__iterator/segmented_iterator.h b/libcxx/include/__iterator/segmented_iterator.h
index af27a7b..5df9737 100644
--- a/libcxx/include/__iterator/segmented_iterator.h
+++ b/libcxx/include/__iterator/segmented_iterator.h
@@ -67,13 +67,13 @@ struct __segmented_iterator_traits;
*/
template <class _Tp, size_t = 0>
-struct __has_specialization : false_type {};
+inline const bool __has_specialization_v = false;
template <class _Tp>
-struct __has_specialization<_Tp, sizeof(_Tp) * 0> : true_type {};
+inline const bool __has_specialization_v<_Tp, sizeof(_Tp) * 0> = true;
template <class _Iterator>
-using __is_segmented_iterator _LIBCPP_NODEBUG = __has_specialization<__segmented_iterator_traits<_Iterator> >;
+inline const bool __is_segmented_iterator_v = __has_specialization_v<__segmented_iterator_traits<_Iterator> >;
template <class _SegmentedIterator>
struct __has_random_access_local_iterator
diff --git a/libcxx/include/__log_hardening_failure b/libcxx/include/__log_hardening_failure
new file mode 100644
index 0000000..d180530
--- /dev/null
+++ b/libcxx/include/__log_hardening_failure
@@ -0,0 +1,42 @@
+// -*- 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___LOG_HARDENING_FAILURE
+#define _LIBCPP___LOG_HARDENING_FAILURE
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+// Hardening logging is not available in the C++03 mode; moreover, it is currently only available in the experimental
+// library.
+#if _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC && !defined(_LIBCPP_CXX03_LANG)
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// This function should never be called directly from the code -- it should only be called through the
+// `_LIBCPP_LOG_HARDENING_FAILURE` macro.
+[[__gnu__::__cold__]] _LIBCPP_EXPORTED_FROM_ABI void __log_hardening_failure(const char* __message) noexcept;
+
+// _LIBCPP_LOG_HARDENING_FAILURE(message)
+//
+// This macro is used to log an error without terminating the program (as is the case for hardening failures if the
+// `observe` assertion semantic is used).
+
+# if !defined(_LIBCPP_LOG_HARDENING_FAILURE)
+# define _LIBCPP_LOG_HARDENING_FAILURE(__message) ::std::__log_hardening_failure(__message)
+# endif // !defined(_LIBCPP_LOG_HARDENING_FAILURE)
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC && !defined(_LIBCPP_CXX03_LANG)
+
+#endif // _LIBCPP___LOG_HARDENING_FAILURE
diff --git a/libcxx/include/__memory/construct_at.h b/libcxx/include/__memory/construct_at.h
index b64e64b..6582691 100644
--- a/libcxx/include/__memory/construct_at.h
+++ b/libcxx/include/__memory/construct_at.h
@@ -33,7 +33,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
template <class _Tp, class... _Args, class = decltype(::new(std::declval<void*>()) _Tp(std::declval<_Args>()...))>
-_LIBCPP_HIDE_FROM_ABI constexpr _Tp* construct_at(_Tp* __location, _Args&&... __args) {
+_LIBCPP_HIDE_FROM_ABI constexpr _Tp* construct_at(_Tp* _LIBCPP_DIAGNOSE_NULLPTR __location, _Args&&... __args) {
_LIBCPP_ASSERT_NON_NULL(__location != nullptr, "null pointer given to construct_at");
return ::new (static_cast<void*>(__location)) _Tp(std::forward<_Args>(__args)...);
}
@@ -73,13 +73,13 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_at(_Tp* __loc) {
#if _LIBCPP_STD_VER >= 17
template <class _Tp, enable_if_t<!is_array_v<_Tp>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void destroy_at(_Tp* __loc) {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void destroy_at(_Tp* _LIBCPP_DIAGNOSE_NULLPTR __loc) {
std::__destroy_at(__loc);
}
# if _LIBCPP_STD_VER >= 20
template <class _Tp, enable_if_t<is_array_v<_Tp>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr void destroy_at(_Tp* __loc) {
+_LIBCPP_HIDE_FROM_ABI constexpr void destroy_at(_Tp* _LIBCPP_DIAGNOSE_NULLPTR __loc) {
std::__destroy_at(__loc);
}
# endif
diff --git a/libcxx/include/__memory_resource/polymorphic_allocator.h b/libcxx/include/__memory_resource/polymorphic_allocator.h
index 1b8711f..6e7a9af 100644
--- a/libcxx/include/__memory_resource/polymorphic_allocator.h
+++ b/libcxx/include/__memory_resource/polymorphic_allocator.h
@@ -135,10 +135,10 @@ public:
piecewise_construct,
__transform_tuple(typename __uses_alloc_ctor< _T1, polymorphic_allocator&, _Args1... >::type(),
std::move(__x),
- typename __make_tuple_indices<sizeof...(_Args1)>::type{}),
+ make_index_sequence<sizeof...(_Args1)>()),
__transform_tuple(typename __uses_alloc_ctor< _T2, polymorphic_allocator&, _Args2... >::type(),
std::move(__y),
- typename __make_tuple_indices<sizeof...(_Args2)>::type{}));
+ make_index_sequence<sizeof...(_Args2)>()));
}
template <class _T1, class _T2>
@@ -194,20 +194,20 @@ public:
private:
template <class... _Args, size_t... _Is>
_LIBCPP_HIDE_FROM_ABI tuple<_Args&&...>
- __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) {
+ __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, index_sequence<_Is...>) {
return std::forward_as_tuple(std::get<_Is>(std::move(__t))...);
}
template <class... _Args, size_t... _Is>
_LIBCPP_HIDE_FROM_ABI tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>
- __transform_tuple(integral_constant<int, 1>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) {
+ __transform_tuple(integral_constant<int, 1>, tuple<_Args...>&& __t, index_sequence<_Is...>) {
using _Tup = tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>;
return _Tup(allocator_arg, *this, std::get<_Is>(std::move(__t))...);
}
template <class... _Args, size_t... _Is>
_LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., polymorphic_allocator&>
- __transform_tuple(integral_constant<int, 2>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) {
+ __transform_tuple(integral_constant<int, 2>, tuple<_Args...>&& __t, index_sequence<_Is...>) {
using _Tup = tuple<_Args&&..., polymorphic_allocator&>;
return _Tup(std::get<_Is>(std::move(__t))..., *this);
}
diff --git a/libcxx/include/__mutex/once_flag.h b/libcxx/include/__mutex/once_flag.h
index 3306449..e384c15 100644
--- a/libcxx/include/__mutex/once_flag.h
+++ b/libcxx/include/__mutex/once_flag.h
@@ -13,9 +13,9 @@
#include <__functional/invoke.h>
#include <__memory/addressof.h>
#include <__memory/shared_count.h> // __libcpp_acquire_load
-#include <__tuple/tuple_indices.h>
#include <__tuple/tuple_size.h>
#include <__utility/forward.h>
+#include <__utility/integer_sequence.h>
#include <__utility/move.h>
#include <cstdint>
#ifndef _LIBCPP_CXX03_LANG
@@ -87,15 +87,12 @@ class __call_once_param {
public:
_LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {}
- _LIBCPP_HIDE_FROM_ABI void operator()() {
- typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index;
- __execute(_Index());
- }
+ _LIBCPP_HIDE_FROM_ABI void operator()() { __execute(__make_index_sequence<tuple_size<_Fp>::value>()); }
private:
template <size_t... _Indices>
- _LIBCPP_HIDE_FROM_ABI void __execute(__tuple_indices<_Indices...>) {
- std::__invoke(std::get<0>(std::move(__f_)), std::get<_Indices>(std::move(__f_))...);
+ _LIBCPP_HIDE_FROM_ABI void __execute(__index_sequence<_Indices...>) {
+ std::__invoke(std::get<_Indices>(std::move(__f_))...);
}
};
diff --git a/libcxx/include/__ranges/zip_transform_view.h b/libcxx/include/__ranges/zip_transform_view.h
new file mode 100644
index 0000000..07aa182f
--- /dev/null
+++ b/libcxx/include/__ranges/zip_transform_view.h
@@ -0,0 +1,357 @@
+// -*- 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___RANGES_ZIP_TRANSFORM_VIEW_H
+#define _LIBCPP___RANGES_ZIP_TRANSFORM_VIEW_H
+
+#include <__config>
+
+#include <__concepts/constructible.h>
+#include <__concepts/convertible_to.h>
+#include <__concepts/derived_from.h>
+#include <__concepts/equality_comparable.h>
+#include <__concepts/invocable.h>
+#include <__functional/invoke.h>
+#include <__iterator/concepts.h>
+#include <__iterator/incrementable_traits.h>
+#include <__iterator/iterator_traits.h>
+#include <__memory/addressof.h>
+#include <__ranges/access.h>
+#include <__ranges/all.h>
+#include <__ranges/concepts.h>
+#include <__ranges/empty_view.h>
+#include <__ranges/movable_box.h>
+#include <__ranges/view_interface.h>
+#include <__ranges/zip_view.h>
+#include <__type_traits/decay.h>
+#include <__type_traits/invoke.h>
+#include <__type_traits/is_object.h>
+#include <__type_traits/is_reference.h>
+#include <__type_traits/is_referenceable.h>
+#include <__type_traits/maybe_const.h>
+#include <__type_traits/remove_cvref.h>
+#include <__utility/forward.h>
+#include <__utility/in_place.h>
+#include <__utility/move.h>
+#include <tuple> // for std::apply
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace ranges {
+
+template <move_constructible _Fn, input_range... _Views>
+ requires(view<_Views> && ...) &&
+ (sizeof...(_Views) > 0) && is_object_v<_Fn> && regular_invocable<_Fn&, range_reference_t<_Views>...> &&
+ __referenceable<invoke_result_t<_Fn&, range_reference_t<_Views>...>>
+class zip_transform_view : public view_interface<zip_transform_view<_Fn, _Views...>> {
+ _LIBCPP_NO_UNIQUE_ADDRESS zip_view<_Views...> __zip_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Fn> __fun_;
+
+ using _InnerView _LIBCPP_NODEBUG = zip_view<_Views...>;
+ template <bool _Const>
+ using __ziperator _LIBCPP_NODEBUG = iterator_t<__maybe_const<_Const, _InnerView>>;
+ template <bool _Const>
+ using __zentinel _LIBCPP_NODEBUG = sentinel_t<__maybe_const<_Const, _InnerView>>;
+
+ template <bool>
+ class __iterator;
+
+ template <bool>
+ class __sentinel;
+
+public:
+ _LIBCPP_HIDE_FROM_ABI zip_transform_view() = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit zip_transform_view(_Fn __fun, _Views... __views)
+ : __zip_(std::move(__views)...), __fun_(in_place, std::move(__fun)) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto begin() { return __iterator<false>(*this, __zip_.begin()); }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+ requires range<const _InnerView> && regular_invocable<const _Fn&, range_reference_t<const _Views>...>
+ {
+ return __iterator<true>(*this, __zip_.begin());
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto end() {
+ if constexpr (common_range<_InnerView>) {
+ return __iterator<false>(*this, __zip_.end());
+ } else {
+ return __sentinel<false>(__zip_.end());
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+ requires range<const _InnerView> && regular_invocable<const _Fn&, range_reference_t<const _Views>...>
+ {
+ if constexpr (common_range<const _InnerView>) {
+ return __iterator<true>(*this, __zip_.end());
+ } else {
+ return __sentinel<true>(__zip_.end());
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+ requires sized_range<_InnerView>
+ {
+ return __zip_.size();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+ requires sized_range<const _InnerView>
+ {
+ return __zip_.size();
+ }
+};
+
+template <class _Fn, class... _Ranges>
+zip_transform_view(_Fn, _Ranges&&...) -> zip_transform_view<_Fn, views::all_t<_Ranges>...>;
+
+template <bool _Const, class _Fn, class... _Views>
+struct __zip_transform_iterator_category_base {};
+
+template <bool _Const, class _Fn, class... _Views>
+ requires forward_range<__maybe_const<_Const, zip_view<_Views...>>>
+struct __zip_transform_iterator_category_base<_Const, _Fn, _Views...> {
+private:
+ template <class _View>
+ using __tag _LIBCPP_NODEBUG = typename iterator_traits<iterator_t<__maybe_const<_Const, _View>>>::iterator_category;
+
+ static consteval auto __get_iterator_category() {
+ if constexpr (!is_reference_v<invoke_result_t<__maybe_const<_Const, _Fn>&,
+ range_reference_t<__maybe_const<_Const, _Views>>...>>) {
+ return input_iterator_tag();
+ } else if constexpr ((derived_from<__tag<_Views>, random_access_iterator_tag> && ...)) {
+ return random_access_iterator_tag();
+ } else if constexpr ((derived_from<__tag<_Views>, bidirectional_iterator_tag> && ...)) {
+ return bidirectional_iterator_tag();
+ } else if constexpr ((derived_from<__tag<_Views>, forward_iterator_tag> && ...)) {
+ return forward_iterator_tag();
+ } else {
+ return input_iterator_tag();
+ }
+ }
+
+public:
+ using iterator_category = decltype(__get_iterator_category());
+};
+
+template <move_constructible _Fn, input_range... _Views>
+ requires(view<_Views> && ...) &&
+ (sizeof...(_Views) > 0) && is_object_v<_Fn> && regular_invocable<_Fn&, range_reference_t<_Views>...> &&
+ __referenceable<invoke_result_t<_Fn&, range_reference_t<_Views>...>>
+template <bool _Const>
+class zip_transform_view<_Fn, _Views...>::__iterator
+ : public __zip_transform_iterator_category_base<_Const, _Fn, _Views...> {
+ using _Parent _LIBCPP_NODEBUG = __maybe_const<_Const, zip_transform_view>;
+ using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _InnerView>;
+
+ friend zip_transform_view<_Fn, _Views...>;
+
+ _Parent* __parent_ = nullptr;
+ __ziperator<_Const> __inner_;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, __ziperator<_Const> __inner)
+ : __parent_(std::addressof(__parent)), __inner_(std::move(__inner)) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto __get_deref_and_invoke() const noexcept {
+ return [&__fun = *__parent_->__fun_](const auto&... __iters) noexcept(noexcept(std::invoke(
+ *__parent_->__fun_, *__iters...))) -> decltype(auto) { return std::invoke(__fun, *__iters...); };
+ }
+
+public:
+ using iterator_concept = typename __ziperator<_Const>::iterator_concept;
+ using value_type =
+ remove_cvref_t<invoke_result_t<__maybe_const<_Const, _Fn>&, range_reference_t<__maybe_const<_Const, _Views>>...>>;
+ using difference_type = range_difference_t<_Base>;
+
+ _LIBCPP_HIDE_FROM_ABI __iterator() = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
+ requires _Const && convertible_to<__ziperator<false>, __ziperator<_Const>>
+ : __parent_(__i.__parent_), __inner_(std::move(__i.__inner_)) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const
+ noexcept(noexcept(std::apply(__get_deref_and_invoke(), __zip_view_iterator_access::__get_underlying(__inner_)))) {
+ return std::apply(__get_deref_and_invoke(), __zip_view_iterator_access::__get_underlying(__inner_));
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+ ++__inner_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
+ requires forward_range<_Base>
+ {
+ auto __tmp = *this;
+ ++*this;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
+ requires bidirectional_range<_Base>
+ {
+ --__inner_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
+ requires bidirectional_range<_Base>
+ {
+ auto __tmp = *this;
+ --*this;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __x)
+ requires random_access_range<_Base>
+ {
+ __inner_ += __x;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __x)
+ requires random_access_range<_Base>
+ {
+ __inner_ -= __x;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const
+ requires random_access_range<_Base>
+ {
+ return std::apply(
+ [&]<class... _Is>(const _Is&... __iters) -> decltype(auto) {
+ return std::invoke(*__parent_->__fun_, __iters[iter_difference_t<_Is>(__n)]...);
+ },
+ __zip_view_iterator_access::__get_underlying(__inner_));
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
+ requires equality_comparable<__ziperator<_Const>>
+ {
+ return __x.__inner_ == __y.__inner_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
+ requires random_access_range<_Base>
+ {
+ return __x.__inner_ <=> __y.__inner_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n)
+ requires random_access_range<_Base>
+ {
+ return __iterator(*__i.__parent_, __i.__inner_ + __n);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i)
+ requires random_access_range<_Base>
+ {
+ return __iterator(*__i.__parent_, __i.__inner_ + __n);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n)
+ requires random_access_range<_Base>
+ {
+ return __iterator(*__i.__parent_, __i.__inner_ - __n);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y)
+ requires sized_sentinel_for<__ziperator<_Const>, __ziperator<_Const>>
+ {
+ return __x.__inner_ - __y.__inner_;
+ }
+};
+
+template <move_constructible _Fn, input_range... _Views>
+ requires(view<_Views> && ...) &&
+ (sizeof...(_Views) > 0) && is_object_v<_Fn> && regular_invocable<_Fn&, range_reference_t<_Views>...> &&
+ __referenceable<invoke_result_t<_Fn&, range_reference_t<_Views>...>>
+template <bool _Const>
+class zip_transform_view<_Fn, _Views...>::__sentinel {
+ __zentinel<_Const> __inner_;
+
+ friend zip_transform_view<_Fn, _Views...>;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(__zentinel<_Const> __inner) : __inner_(__inner) {}
+
+public:
+ _LIBCPP_HIDE_FROM_ABI __sentinel() = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __i)
+ requires _Const && convertible_to<__zentinel<false>, __zentinel<_Const>>
+ : __inner_(__i.__inner_) {}
+
+ template <bool _OtherConst>
+ requires sentinel_for<__zentinel<_Const>, __ziperator<_OtherConst>>
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
+ return __x.__inner_ == __y.__inner_;
+ }
+
+ template <bool _OtherConst>
+ requires sized_sentinel_for<__zentinel<_Const>, __ziperator<_OtherConst>>
+ _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _InnerView>>
+ operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
+ return __x.__inner_ - __y.__inner_;
+ }
+
+ template <bool _OtherConst>
+ requires sized_sentinel_for<__zentinel<_Const>, __ziperator<_OtherConst>>
+ _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _InnerView>>
+ operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) {
+ return __x.__inner_ - __y.__inner_;
+ }
+};
+
+namespace views {
+namespace __zip_transform {
+
+struct __fn {
+ template <class _Fn>
+ requires(move_constructible<decay_t<_Fn>> && regular_invocable<decay_t<_Fn>&> &&
+ is_object_v<invoke_result_t<decay_t<_Fn>&>>)
+ _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Fn&&) const
+ noexcept(noexcept(auto(views::empty<decay_t<invoke_result_t<decay_t<_Fn>&>>>))) {
+ return views::empty<decay_t<invoke_result_t<decay_t<_Fn>&>>>;
+ }
+
+ template <class _Fn, class... _Ranges>
+ requires(sizeof...(_Ranges) > 0)
+ _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Fn&& __fun, _Ranges&&... __rs) const
+ noexcept(noexcept(zip_transform_view(std::forward<_Fn>(__fun), std::forward<_Ranges>(__rs)...)))
+ -> decltype(zip_transform_view(std::forward<_Fn>(__fun), std::forward<_Ranges>(__rs)...)) {
+ return zip_transform_view(std::forward<_Fn>(__fun), std::forward<_Ranges>(__rs)...);
+ }
+};
+
+} // namespace __zip_transform
+inline namespace __cpo {
+inline constexpr auto zip_transform = __zip_transform::__fn{};
+} // namespace __cpo
+} // namespace views
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___RANGES_ZIP_TRANSFORM_VIEW_H
diff --git a/libcxx/include/__ranges/zip_view.h b/libcxx/include/__ranges/zip_view.h
index e2a194e..ce00c98 100644
--- a/libcxx/include/__ranges/zip_view.h
+++ b/libcxx/include/__ranges/zip_view.h
@@ -235,6 +235,13 @@ struct __zip_view_iterator_category_base<_Const, _Views...> {
using iterator_category = input_iterator_tag;
};
+struct __zip_view_iterator_access {
+ template <class _Iter>
+ _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __get_underlying(_Iter& __iter) noexcept {
+ return (__iter.__current_);
+ }
+};
+
template <input_range... _Views>
requires(view<_Views> && ...) && (sizeof...(_Views) > 0)
template <bool _Const>
@@ -255,6 +262,7 @@ class zip_view<_Views...>::__iterator : public __zip_view_iterator_category_base
static constexpr bool __is_zip_view_iterator = true;
friend struct __product_iterator_traits<__iterator>;
+ friend __zip_view_iterator_access;
public:
using iterator_concept = decltype(ranges::__get_zip_view_iterator_tag<_Const, _Views...>());
diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h
index 1b51571..a3b672b 100644
--- a/libcxx/include/__thread/thread.h
+++ b/libcxx/include/__thread/thread.h
@@ -155,8 +155,8 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) {
# ifndef _LIBCPP_CXX03_LANG
template <class _TSp, class _Fp, class... _Args, size_t... _Indices>
-inline _LIBCPP_HIDE_FROM_ABI void __thread_execute(tuple<_TSp, _Fp, _Args...>& __t, __tuple_indices<_Indices...>) {
- std::__invoke(std::move(std::get<1>(__t)), std::move(std::get<_Indices>(__t))...);
+inline _LIBCPP_HIDE_FROM_ABI void __thread_execute(tuple<_TSp, _Fp, _Args...>& __t, __index_sequence<_Indices...>) {
+ std::__invoke(std::move(std::get<_Indices + 1>(__t))...);
}
template <class _Fp>
@@ -164,8 +164,7 @@ _LIBCPP_HIDE_FROM_ABI void* __thread_proxy(void* __vp) {
// _Fp = tuple< unique_ptr<__thread_struct>, Functor, Args...>
unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
__thread_local_data().set_pointer(std::get<0>(*__p.get()).release());
- typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index;
- std::__thread_execute(*__p.get(), _Index());
+ std::__thread_execute(*__p.get(), __make_index_sequence<tuple_size<_Fp>::value - 1>());
return nullptr;
}
diff --git a/libcxx/include/__tuple/make_tuple_types.h b/libcxx/include/__tuple/make_tuple_types.h
index a5c9bcf..3c22ec8 100644
--- a/libcxx/include/__tuple/make_tuple_types.h
+++ b/libcxx/include/__tuple/make_tuple_types.h
@@ -14,12 +14,12 @@
#include <__fwd/array.h>
#include <__fwd/tuple.h>
#include <__tuple/tuple_element.h>
-#include <__tuple/tuple_indices.h>
#include <__tuple/tuple_size.h>
#include <__tuple/tuple_types.h>
#include <__type_traits/copy_cvref.h>
#include <__type_traits/remove_cvref.h>
#include <__type_traits/remove_reference.h>
+#include <__utility/integer_sequence.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -38,38 +38,35 @@ template <class _TupleTypes, class _TupleIndices>
struct __make_tuple_types_flat;
template <template <class...> class _Tuple, class... _Types, size_t... _Idx>
-struct __make_tuple_types_flat<_Tuple<_Types...>, __tuple_indices<_Idx...>> {
+struct __make_tuple_types_flat<_Tuple<_Types...>, __index_sequence<_Idx...>> {
// Specialization for pair, tuple, and __tuple_types
template <class _Tp>
using __apply_quals _LIBCPP_NODEBUG = __tuple_types<__copy_cvref_t<_Tp, __type_pack_element<_Idx, _Types...>>...>;
};
template <class _Vt, size_t _Np, size_t... _Idx>
-struct __make_tuple_types_flat<array<_Vt, _Np>, __tuple_indices<_Idx...>> {
+struct __make_tuple_types_flat<array<_Vt, _Np>, __index_sequence<_Idx...>> {
template <size_t>
using __value_type _LIBCPP_NODEBUG = _Vt;
template <class _Tp>
using __apply_quals _LIBCPP_NODEBUG = __tuple_types<__copy_cvref_t<_Tp, __value_type<_Idx>>...>;
};
-template <class _Tp,
- size_t _Ep = tuple_size<__libcpp_remove_reference_t<_Tp> >::value,
- size_t _Sp = 0,
- bool _SameSize = (_Ep == tuple_size<__libcpp_remove_reference_t<_Tp> >::value)>
+template <class _Tp>
struct __make_tuple_types {
- static_assert(_Sp <= _Ep, "__make_tuple_types input error");
using _RawTp _LIBCPP_NODEBUG = __remove_cvref_t<_Tp>;
- using _Maker _LIBCPP_NODEBUG = __make_tuple_types_flat<_RawTp, typename __make_tuple_indices<_Ep, _Sp>::type>;
- using type _LIBCPP_NODEBUG = typename _Maker::template __apply_quals<_Tp>;
+ using _Maker _LIBCPP_NODEBUG =
+ __make_tuple_types_flat<_RawTp, __make_index_sequence<tuple_size<__libcpp_remove_reference_t<_Tp>>::value>>;
+ using type _LIBCPP_NODEBUG = typename _Maker::template __apply_quals<_Tp>;
};
-template <class... _Types, size_t _Ep>
-struct __make_tuple_types<tuple<_Types...>, _Ep, 0, true> {
+template <class... _Types>
+struct __make_tuple_types<tuple<_Types...>> {
using type _LIBCPP_NODEBUG = __tuple_types<_Types...>;
};
-template <class... _Types, size_t _Ep>
-struct __make_tuple_types<__tuple_types<_Types...>, _Ep, 0, true> {
+template <class... _Types>
+struct __make_tuple_types<__tuple_types<_Types...>> {
using type _LIBCPP_NODEBUG = __tuple_types<_Types...>;
};
diff --git a/libcxx/include/__tuple/tuple_element.h b/libcxx/include/__tuple/tuple_element.h
index f67c867..607ac3a 100644
--- a/libcxx/include/__tuple/tuple_element.h
+++ b/libcxx/include/__tuple/tuple_element.h
@@ -11,7 +11,6 @@
#include <__config>
#include <__cstddef/size_t.h>
-#include <__tuple/tuple_indices.h>
#include <__tuple/tuple_types.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__tuple/tuple_indices.h b/libcxx/include/__tuple/tuple_indices.h
deleted file mode 100644
index 25dc9ec..0000000
--- a/libcxx/include/__tuple/tuple_indices.h
+++ /dev/null
@@ -1,37 +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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef _LIBCPP___TUPLE_MAKE_TUPLE_INDICES_H
-#define _LIBCPP___TUPLE_MAKE_TUPLE_INDICES_H
-
-#include <__config>
-#include <__cstddef/size_t.h>
-#include <__utility/integer_sequence.h>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-# pragma GCC system_header
-#endif
-
-#ifndef _LIBCPP_CXX03_LANG
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-template <size_t...>
-struct __tuple_indices {};
-
-template <size_t _Ep, size_t _Sp = 0>
-struct __make_tuple_indices {
- static_assert(_Sp <= _Ep, "__make_tuple_indices input error");
- typedef __make_indices_imp<_Ep, _Sp> type;
-};
-
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP_CXX03_LANG
-
-#endif // _LIBCPP___TUPLE_MAKE_TUPLE_INDICES_H
diff --git a/libcxx/include/__utility/integer_sequence.h b/libcxx/include/__utility/integer_sequence.h
index d1c6e53..329826a 100644
--- a/libcxx/include/__utility/integer_sequence.h
+++ b/libcxx/include/__utility/integer_sequence.h
@@ -17,57 +17,41 @@
# pragma GCC system_header
#endif
+#ifndef _LIBCPP_CXX03_LANG
+
_LIBCPP_BEGIN_NAMESPACE_STD
-template <size_t...>
-struct __tuple_indices;
+# if __has_builtin(__make_integer_seq)
+template <template <class _Tp, _Tp...> class _BaseType, class _Tp, _Tp _SequenceSize>
+using __make_integer_sequence_impl _LIBCPP_NODEBUG = __make_integer_seq<_BaseType, _Tp, _SequenceSize>;
+# else
+template <template <class _Tp, _Tp...> class _BaseType, class _Tp, _Tp _SequenceSize>
+using __make_integer_sequence_impl _LIBCPP_NODEBUG = _BaseType<_Tp, __integer_pack(_SequenceSize)...>;
+# endif
-template <class _IdxType, _IdxType... _Values>
+template <class _Tp, _Tp... _Indices>
struct __integer_sequence {
- template <template <class _OIdxType, _OIdxType...> class _ToIndexSeq, class _ToIndexType>
- using __convert _LIBCPP_NODEBUG = _ToIndexSeq<_ToIndexType, _Values...>;
-
- template <size_t _Sp>
- using __to_tuple_indices _LIBCPP_NODEBUG = __tuple_indices<(_Values + _Sp)...>;
+ using value_type = _Tp;
+ static_assert(is_integral<_Tp>::value, "std::integer_sequence can only be instantiated with an integral type");
+ static _LIBCPP_HIDE_FROM_ABI constexpr size_t size() noexcept { return sizeof...(_Indices); }
};
-#if __has_builtin(__make_integer_seq)
-template <size_t _Ep, size_t _Sp>
-using __make_indices_imp _LIBCPP_NODEBUG =
- typename __make_integer_seq<__integer_sequence, size_t, _Ep - _Sp>::template __to_tuple_indices<_Sp>;
-#elif __has_builtin(__integer_pack)
-template <size_t _Ep, size_t _Sp>
-using __make_indices_imp _LIBCPP_NODEBUG =
- typename __integer_sequence<size_t, __integer_pack(_Ep - _Sp)...>::template __to_tuple_indices<_Sp>;
-#else
-# error "No known way to get an integer pack from the compiler"
-#endif
+template <size_t... _Indices>
+using __index_sequence _LIBCPP_NODEBUG = __integer_sequence<size_t, _Indices...>;
-#if _LIBCPP_STD_VER >= 14
+template <size_t _SequenceSize>
+using __make_index_sequence _LIBCPP_NODEBUG = __make_integer_sequence_impl<__integer_sequence, size_t, _SequenceSize>;
-template <class _Tp, _Tp... _Ip>
-struct integer_sequence {
- typedef _Tp value_type;
- static_assert(is_integral<_Tp>::value, "std::integer_sequence can only be instantiated with an integral type");
- static _LIBCPP_HIDE_FROM_ABI constexpr size_t size() noexcept { return sizeof...(_Ip); }
-};
+# if _LIBCPP_STD_VER >= 14
+
+template <class _Tp, _Tp... _Indices>
+struct integer_sequence : __integer_sequence<_Tp, _Indices...> {};
template <size_t... _Ip>
using index_sequence = integer_sequence<size_t, _Ip...>;
-# if __has_builtin(__make_integer_seq)
-
template <class _Tp, _Tp _Ep>
-using make_integer_sequence _LIBCPP_NODEBUG = __make_integer_seq<integer_sequence, _Tp, _Ep>;
-
-# elif __has_builtin(__integer_pack)
-
-template <class _Tp, _Tp _SequenceSize>
-using make_integer_sequence _LIBCPP_NODEBUG = integer_sequence<_Tp, __integer_pack(_SequenceSize)...>;
-
-# else
-# error "No known way to get an integer pack from the compiler"
-# endif
+using make_integer_sequence _LIBCPP_NODEBUG = __make_integer_sequence_impl<integer_sequence, _Tp, _Ep>;
template <size_t _Np>
using make_index_sequence = make_integer_sequence<size_t, _Np>;
@@ -75,16 +59,18 @@ using make_index_sequence = make_integer_sequence<size_t, _Np>;
template <class... _Tp>
using index_sequence_for = make_index_sequence<sizeof...(_Tp)>;
-# if _LIBCPP_STD_VER >= 20
+# if _LIBCPP_STD_VER >= 20
// Executes __func for every element in an index_sequence.
template <size_t... _Index, class _Function>
_LIBCPP_HIDE_FROM_ABI constexpr void __for_each_index_sequence(index_sequence<_Index...>, _Function __func) {
(__func.template operator()<_Index>(), ...);
}
-# endif // _LIBCPP_STD_VER >= 20
+# endif // _LIBCPP_STD_VER >= 20
-#endif // _LIBCPP_STD_VER >= 14
+# endif // _LIBCPP_STD_VER >= 14
_LIBCPP_END_NAMESPACE_STD
+#endif // _LIBCPP_CXX03_LANG
+
#endif // _LIBCPP___UTILITY_INTEGER_SEQUENCE_H
diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index dbacbce..33694c52 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -18,7 +18,6 @@
#include <__fwd/array.h>
#include <__fwd/pair.h>
#include <__fwd/tuple.h>
-#include <__tuple/tuple_indices.h>
#include <__tuple/tuple_like_no_subrange.h>
#include <__tuple/tuple_size.h>
#include <__type_traits/common_reference.h>
@@ -40,6 +39,7 @@
#include <__type_traits/unwrap_ref.h>
#include <__utility/declval.h>
#include <__utility/forward.h>
+#include <__utility/integer_sequence.h>
#include <__utility/move.h>
#include <__utility/piecewise_construct.h>
@@ -225,8 +225,8 @@ struct pair
: pair(__pc,
__first_args,
__second_args,
- typename __make_tuple_indices<sizeof...(_Args1)>::type(),
- typename __make_tuple_indices<sizeof...(_Args2) >::type()) {}
+ __make_index_sequence<sizeof...(_Args1)>(),
+ __make_index_sequence<sizeof...(_Args2)>()) {}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair&
operator=(__conditional_t<is_copy_assignable<first_type>::value && is_copy_assignable<second_type>::value,
@@ -440,8 +440,8 @@ private:
pair(piecewise_construct_t,
tuple<_Args1...>& __first_args,
tuple<_Args2...>& __second_args,
- __tuple_indices<_I1...>,
- __tuple_indices<_I2...>)
+ __index_sequence<_I1...>,
+ __index_sequence<_I2...>)
: first(std::forward<_Args1>(std::get<_I1>(__first_args))...),
second(std::forward<_Args2>(std::get<_I2>(__second_args))...) {}
#endif
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 4e0d76f..4307e78 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -341,59 +341,67 @@ public:
}
#endif
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT {
return this->__alloc_;
}
//
// Iterators
//
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT {
return __make_iter(__add_alignment_assumption(this->__begin_));
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT {
return __make_iter(__add_alignment_assumption(this->__begin_));
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT {
return __make_iter(__add_alignment_assumption(this->__end_));
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT {
return __make_iter(__add_alignment_assumption(this->__end_));
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT {
return reverse_iterator(end());
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator
+ rbegin() const _NOEXCEPT {
return const_reverse_iterator(end());
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT {
return reverse_iterator(begin());
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT {
return const_reverse_iterator(begin());
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT {
+ return begin();
+ }
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT {
+ return end();
+ }
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator
+ crbegin() const _NOEXCEPT {
return rbegin();
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); }
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT {
+ return rend();
+ }
//
// [vector.capacity], capacity
//
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT {
return static_cast<size_type>(this->__end_ - this->__begin_);
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT {
return static_cast<size_type>(this->__cap_ - this->__begin_);
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT {
return this->__begin_ == this->__end_;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
return std::min<size_type>(__alloc_traits::max_size(this->__alloc_), numeric_limits<difference_type>::max());
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n);
@@ -402,38 +410,39 @@ public:
//
// element access
//
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference operator[](size_type __n) _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference operator[](size_type __n) _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds");
return this->__begin_[__n];
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __n) const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference
+ operator[](size_type __n) const _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds");
return this->__begin_[__n];
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference at(size_type __n) {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference at(size_type __n) {
if (__n >= size())
this->__throw_out_of_range();
return this->__begin_[__n];
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __n) const {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __n) const {
if (__n >= size())
this->__throw_out_of_range();
return this->__begin_[__n];
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector");
return *this->__begin_;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector");
return *this->__begin_;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector");
return *(this->__end_ - 1);
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector");
return *(this->__end_ - 1);
}
@@ -441,11 +450,11 @@ public:
//
// [vector.data], data access
//
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI value_type* data() _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI value_type* data() _NOEXCEPT {
return std::__to_address(this->__begin_);
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const value_type* data() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const value_type* data() const _NOEXCEPT {
return std::__to_address(this->__begin_);
}
diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h
index e921e65..bd7b28e 100644
--- a/libcxx/include/__vector/vector_bool.h
+++ b/libcxx/include/__vector/vector_bool.h
@@ -234,74 +234,89 @@ public:
}
#endif
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 allocator_type get_allocator() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 allocator_type get_allocator() const _NOEXCEPT {
return allocator_type(this->__alloc_);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type max_size() const _NOEXCEPT;
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type capacity() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type max_size() const _NOEXCEPT;
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type capacity() const _NOEXCEPT {
return __internal_cap_to_external(__cap_);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type size() const _NOEXCEPT { return __size_; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type size() const _NOEXCEPT {
+ return __size_;
+ }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool empty() const _NOEXCEPT {
return __size_ == 0;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reserve(size_type __n);
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void shrink_to_fit() _NOEXCEPT;
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator begin() _NOEXCEPT { return __make_iter(0); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator begin() const _NOEXCEPT { return __make_iter(0); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator end() _NOEXCEPT { return __make_iter(__size_); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator end() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator begin() _NOEXCEPT {
+ return __make_iter(0);
+ }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator begin() const _NOEXCEPT {
+ return __make_iter(0);
+ }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator end() _NOEXCEPT {
+ return __make_iter(__size_);
+ }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator end() const _NOEXCEPT {
return __make_iter(__size_);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reverse_iterator rbegin() _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reverse_iterator rbegin() _NOEXCEPT {
return reverse_iterator(end());
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator rbegin() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator
+ rbegin() const _NOEXCEPT {
return const_reverse_iterator(end());
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reverse_iterator rend() _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reverse_iterator rend() _NOEXCEPT {
return reverse_iterator(begin());
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator rend() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator rend() const _NOEXCEPT {
return const_reverse_iterator(begin());
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator cbegin() const _NOEXCEPT { return __make_iter(0); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator cend() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator cbegin() const _NOEXCEPT {
+ return __make_iter(0);
+ }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator cend() const _NOEXCEPT {
return __make_iter(__size_);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator crbegin() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator
+ crbegin() const _NOEXCEPT {
return rbegin();
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator crend() const _NOEXCEPT { return rend(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator crend() const _NOEXCEPT {
+ return rend();
+ }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](size_type __n) {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](size_type __n) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector<bool>::operator[] index out of bounds");
return __make_ref(__n);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference operator[](size_type __n) const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference
+ operator[](size_type __n) const {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector<bool>::operator[] index out of bounds");
return __make_ref(__n);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference at(size_type __n);
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference at(size_type __n) const;
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference at(size_type __n);
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference at(size_type __n) const;
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference front() {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference front() {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector<bool>::front() called on an empty vector");
return __make_ref(0);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference front() const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference front() const {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector<bool>::front() called on an empty vector");
return __make_ref(0);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference back() {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference back() {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector<bool>::back() called on an empty vector");
return __make_ref(__size_ - 1);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference back() const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference back() const {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector<bool>::back() called on an empty vector");
return __make_ref(__size_ - 1);
}
diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index d109f27..e2b4615 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -147,7 +147,6 @@ template <size_t N> struct hash<std::bitset<N>>;
# include <__functional/hash.h>
# include <__functional/identity.h>
# include <__functional/unary_function.h>
-# include <__tuple/tuple_indices.h>
# include <__type_traits/enable_if.h>
# include <__type_traits/integral_constant.h>
# include <__type_traits/is_char_like_type.h>
@@ -314,7 +313,7 @@ private:
_LIBCPP_HIDE_FROM_ABI void __init(unsigned long long __v, true_type) _NOEXCEPT;
# else
template <size_t... _Indices>
- _LIBCPP_HIDE_FROM_ABI constexpr __bitset(unsigned long long __v, std::__tuple_indices<_Indices...>) _NOEXCEPT
+ _LIBCPP_HIDE_FROM_ABI constexpr __bitset(unsigned long long __v, __index_sequence<_Indices...>) _NOEXCEPT
: __first_{static_cast<__storage_type>(__v >> (_Indices * __bits_per_word))...} {}
# endif // _LIBCPP_CXX03_LANG
};
@@ -352,10 +351,9 @@ template <size_t _N_words, size_t _Size>
inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
# ifndef _LIBCPP_CXX03_LANG
: __bitset(__v,
- std::__make_indices_imp< (_N_words < (sizeof(unsigned long long) - 1) / sizeof(__storage_type) + 1)
- ? _N_words
- : (sizeof(unsigned long long) - 1) / sizeof(__storage_type) + 1,
- 0>{})
+ __make_index_sequence<(_N_words < (sizeof(unsigned long long) - 1) / sizeof(__storage_type) + 1)
+ ? _N_words
+ : (sizeof(unsigned long long) - 1) / sizeof(__storage_type) + 1>())
# endif
{
# ifdef _LIBCPP_CXX03_LANG
diff --git a/libcxx/include/deque b/libcxx/include/deque
index e33e7d3..395a107 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -461,9 +461,8 @@ private:
__deque_iterator<_ValueType, _Pointer, _Reference, _MapPointer, _DiffType, _BlockSize>;
public:
- using __is_segmented_iterator _LIBCPP_NODEBUG = true_type;
- using __segment_iterator _LIBCPP_NODEBUG = _MapPointer;
- using __local_iterator _LIBCPP_NODEBUG = _Pointer;
+ using __segment_iterator _LIBCPP_NODEBUG = _MapPointer;
+ using __local_iterator _LIBCPP_NODEBUG = _Pointer;
static _LIBCPP_HIDE_FROM_ABI __segment_iterator __segment(_Iterator __iter) { return __iter.__m_iter_; }
static _LIBCPP_HIDE_FROM_ABI __local_iterator __local(_Iterator __iter) { return __iter.__ptr_; }
diff --git a/libcxx/include/future b/libcxx/include/future
index abdd82d..3df9dc9 100644
--- a/libcxx/include/future
+++ b/libcxx/include/future
@@ -1842,15 +1842,12 @@ public:
_LIBCPP_HIDE_FROM_ABI __async_func(__async_func&& __f) : __f_(std::move(__f.__f_)) {}
- _LIBCPP_HIDE_FROM_ABI _Rp operator()() {
- typedef typename __make_tuple_indices<1 + sizeof...(_Args), 1>::type _Index;
- return __execute(_Index());
- }
+ _LIBCPP_HIDE_FROM_ABI _Rp operator()() { return __execute(__make_index_sequence<sizeof...(_Args) + 1>()); }
private:
template <size_t... _Indices>
- _LIBCPP_HIDE_FROM_ABI _Rp __execute(__tuple_indices<_Indices...>) {
- return std::__invoke(std::move(std::get<0>(__f_)), std::move(std::get<_Indices>(__f_))...);
+ _LIBCPP_HIDE_FROM_ABI _Rp __execute(__index_sequence<_Indices...>) {
+ return std::__invoke(std::move(std::get<_Indices>(__f_))...);
}
};
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 78607f2..5857a83 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1338,6 +1338,7 @@ module std [system] {
module enable_insertable { header "__format/enable_insertable.h" }
module escaped_output_table { header "__format/escaped_output_table.h" }
module extended_grapheme_cluster_table { header "__format/extended_grapheme_cluster_table.h" }
+ module fmt_pair_like { header "__format/fmt_pair_like.h" }
module format_arg { header "__format/format_arg.h" }
module format_arg_store { header "__format/format_arg_store.h" }
module format_args { header "__format/format_args.h" }
@@ -1943,6 +1944,9 @@ module std [system] {
header "__ranges/zip_view.h"
export std.utility.pair
}
+ module zip_transform_view {
+ header "__ranges/zip_transform_view.h"
+ }
header "ranges"
export *
@@ -2110,7 +2114,6 @@ module std [system] {
module make_tuple_types { header "__tuple/make_tuple_types.h" }
module sfinae_helpers { header "__tuple/sfinae_helpers.h" }
module tuple_element { header "__tuple/tuple_element.h" }
- module tuple_indices { header "__tuple/tuple_indices.h" }
module tuple_like_ext { header "__tuple/tuple_like_ext.h" }
module tuple_like_no_subrange { header "__tuple/tuple_like_no_subrange.h" }
module tuple_like { header "__tuple/tuple_like.h" }
@@ -2353,6 +2356,9 @@ module std [system] {
header "__std_mbstate_t.h"
export *
}
+ module log_hardening_failure {
+ header "__log_hardening_failure"
+ }
module verbose_abort {
header "__verbose_abort"
}
diff --git a/libcxx/include/mutex b/libcxx/include/mutex
index dc8e711..78d8c8a 100644
--- a/libcxx/include/mutex
+++ b/libcxx/include/mutex
@@ -469,17 +469,14 @@ public:
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI scoped_lock(adopt_lock_t, _MArgs&... __margs) : __t_(__margs...) {}
- _LIBCPP_HIDE_FROM_ABI ~scoped_lock() {
- typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices;
- __unlock_unpack(_Indices{}, __t_);
- }
+ _LIBCPP_HIDE_FROM_ABI ~scoped_lock() { __unlock_unpack(make_index_sequence<sizeof...(_MArgs)>(), __t_); }
scoped_lock(scoped_lock const&) = delete;
scoped_lock& operator=(scoped_lock const&) = delete;
private:
template <size_t... _Indx>
- _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) {
+ _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(index_sequence<_Indx...>, _MutexTuple& __mt) {
(std::get<_Indx>(__mt).unlock(), ...);
}
diff --git a/libcxx/include/print b/libcxx/include/print
index be05d30..0ff314c 100644
--- a/libcxx/include/print
+++ b/libcxx/include/print
@@ -329,7 +329,8 @@ __vprint_unicode([[maybe_unused]] FILE* __stream,
} // namespace __print
template <class... _Args>
-_LIBCPP_HIDE_FROM_ABI void print(FILE* __stream, format_string<_Args...> __fmt, _Args&&... __args) {
+_LIBCPP_HIDE_FROM_ABI void
+print(FILE* _LIBCPP_DIAGNOSE_NULLPTR __stream, format_string<_Args...> __fmt, _Args&&... __args) {
# if _LIBCPP_HAS_UNICODE
if constexpr (__print::__use_unicode_execution_charset)
__print::__vprint_unicode(__stream, __fmt.get(), std::make_format_args(__args...), false);
@@ -346,7 +347,8 @@ _LIBCPP_HIDE_FROM_ABI void print(format_string<_Args...> __fmt, _Args&&... __arg
}
template <class... _Args>
-_LIBCPP_HIDE_FROM_ABI void println(FILE* __stream, format_string<_Args...> __fmt, _Args&&... __args) {
+_LIBCPP_HIDE_FROM_ABI void
+println(FILE* _LIBCPP_DIAGNOSE_NULLPTR __stream, format_string<_Args...> __fmt, _Args&&... __args) {
# if _LIBCPP_HAS_UNICODE
// Note the wording in the Standard is inefficient. The output of
// std::format is a std::string which is then copied. This solution
@@ -361,7 +363,7 @@ _LIBCPP_HIDE_FROM_ABI void println(FILE* __stream, format_string<_Args...> __fmt
}
template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
-_LIBCPP_HIDE_FROM_ABI inline void println(FILE* __stream) {
+_LIBCPP_HIDE_FROM_ABI inline void println(FILE* _LIBCPP_DIAGNOSE_NULLPTR __stream) {
std::print(__stream, "\n");
}
@@ -377,7 +379,8 @@ _LIBCPP_HIDE_FROM_ABI void println(format_string<_Args...> __fmt, _Args&&... __a
# if _LIBCPP_HAS_UNICODE
template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
-_LIBCPP_HIDE_FROM_ABI inline void vprint_unicode(FILE* __stream, string_view __fmt, format_args __args) {
+_LIBCPP_HIDE_FROM_ABI inline void
+vprint_unicode(FILE* _LIBCPP_DIAGNOSE_NULLPTR __stream, string_view __fmt, format_args __args) {
__print::__vprint_unicode(__stream, __fmt, __args, false);
}
@@ -389,7 +392,8 @@ _LIBCPP_HIDE_FROM_ABI inline void vprint_unicode(string_view __fmt, format_args
# endif // _LIBCPP_HAS_UNICODE
template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
-_LIBCPP_HIDE_FROM_ABI inline void vprint_nonunicode(FILE* __stream, string_view __fmt, format_args __args) {
+_LIBCPP_HIDE_FROM_ABI inline void
+vprint_nonunicode(FILE* _LIBCPP_DIAGNOSE_NULLPTR __stream, string_view __fmt, format_args __args) {
__print::__vprint_nonunicode(__stream, __fmt, __args, false);
}
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 2a6321b..96d7a6b 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -339,6 +339,16 @@ namespace std::ranges {
namespace views { inline constexpr unspecified zip = unspecified; } // C++23
+ // [range.zip.transform], zip transform view
+ template<move_constructible F, input_range... Views>
+ requires (view<Views> && ...) && (sizeof...(Views) > 0) && is_object_v<F> &&
+ regular_invocable<F&, range_reference_t<Views>...> &&
+ can-reference<invoke_result_t<F&, range_reference_t<Views>...>>
+ class zip_transform_view; // C++23
+
+ namespace views { inline constexpr unspecified zip_transform = unspecified; } // C++23
+
+
// [range.as.rvalue]
template <view V>
requires input_range<V>
@@ -439,6 +449,7 @@ namespace std {
# include <__ranges/join_with_view.h>
# include <__ranges/repeat_view.h>
# include <__ranges/to.h>
+# include <__ranges/zip_transform_view.h>
# include <__ranges/zip_view.h>
# endif
diff --git a/libcxx/include/regex b/libcxx/include/regex
index bbc21e2..9bbc3a6 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -2120,7 +2120,7 @@ public:
__ranges_.push_back(
std::make_pair(__traits_.transform(__b.begin(), __b.end()), __traits_.transform(__e.begin(), __e.end())));
} else {
- if (__b.size() != 1 || __e.size() != 1)
+ if (__b.size() != 1 || __e.size() != 1 || char_traits<typename string_type::value_type>::lt(__e[0], __b[0]))
std::__throw_regex_error<regex_constants::error_range>();
if (__icase_) {
__b[0] = __traits_.translate_nocase(__b[0]);
diff --git a/libcxx/include/scoped_allocator b/libcxx/include/scoped_allocator
index 7b8a9c9..74effc5 100644
--- a/libcxx/include/scoped_allocator
+++ b/libcxx/include/scoped_allocator
@@ -434,10 +434,10 @@ public:
piecewise_construct,
__transform_tuple(typename __uses_alloc_ctor< _T1, inner_allocator_type&, _Args1... >::type(),
std::move(__x),
- typename __make_tuple_indices<sizeof...(_Args1)>::type{}),
+ __make_index_sequence<sizeof...(_Args1)>()),
__transform_tuple(typename __uses_alloc_ctor< _T2, inner_allocator_type&, _Args2... >::type(),
std::move(__y),
- typename __make_tuple_indices<sizeof...(_Args2)>::type{}));
+ __make_index_sequence<sizeof...(_Args2)>()));
}
template <class _T1, class _T2>
@@ -503,20 +503,20 @@ private:
template <class... _Args, size_t... _Idx>
_LIBCPP_HIDE_FROM_ABI tuple<_Args&&...>
- __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, __tuple_indices<_Idx...>) {
+ __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, __index_sequence<_Idx...>) {
return std::forward_as_tuple(std::get<_Idx>(std::move(__t))...);
}
template <class... _Args, size_t... _Idx>
_LIBCPP_HIDE_FROM_ABI tuple<allocator_arg_t, inner_allocator_type&, _Args&&...>
- __transform_tuple(integral_constant<int, 1>, tuple<_Args...>&& __t, __tuple_indices<_Idx...>) {
+ __transform_tuple(integral_constant<int, 1>, tuple<_Args...>&& __t, __index_sequence<_Idx...>) {
using _Tup = tuple<allocator_arg_t, inner_allocator_type&, _Args&&...>;
return _Tup(allocator_arg, inner_allocator(), std::get<_Idx>(std::move(__t))...);
}
template <class... _Args, size_t... _Idx>
_LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., inner_allocator_type&>
- __transform_tuple(integral_constant<int, 2>, tuple<_Args...>&& __t, __tuple_indices<_Idx...>) {
+ __transform_tuple(integral_constant<int, 2>, tuple<_Args...>&& __t, __index_sequence<_Idx...>) {
using _Tup = tuple<_Args&&..., inner_allocator_type&>;
return _Tup(std::get<_Idx>(std::move(__t))..., inner_allocator());
}
diff --git a/libcxx/include/string b/libcxx/include/string
index 788af36..98297d0 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -1065,13 +1065,15 @@ public:
basic_string(nullptr_t) = delete;
# endif
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s, size_type __n) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s, size_type __n)
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "basic_string(const char*, n) detected nullptr");
__init(__s, __n);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
basic_string(const _CharT* __s, size_type __n, const _Allocator& __a)
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero")
: __alloc_(__a) {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "basic_string(const char*, n, allocator) detected nullptr");
__init(__s, __n);
@@ -1394,7 +1396,8 @@ public:
return append(__sv.data() + __pos, std::min(__n, __sz - __pos));
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(const value_type* __s, size_type __n);
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(const value_type* __s, size_type __n)
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero");
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s);
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(size_type __n, value_type __c);
@@ -1521,8 +1524,9 @@ public:
return assign(__sv.data() + __pos, std::min(__n, __sz - __pos));
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(const value_type* __s, size_type __n);
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(const value_type* __s);
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(const value_type* __s, size_type __n)
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero");
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s);
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(size_type __n, value_type __c);
template <class _InputIterator, __enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> = 0>
@@ -1593,7 +1597,8 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string&
insert(size_type __pos1, const basic_string& __str, size_type __pos2, size_type __n = npos);
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& insert(size_type __pos, const value_type* __s, size_type __n);
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& insert(size_type __pos, const value_type* __s, size_type __n)
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero");
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& insert(size_type __pos, const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s);
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& insert(size_type __pos, size_type __n, value_type __c);
_LIBCPP_CONSTEXPR_SINCE_CXX20 iterator insert(const_iterator __pos, value_type __c);
@@ -1673,8 +1678,10 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string&
- replace(size_type __pos, size_type __n1, const value_type* __s, size_type __n2);
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& replace(size_type __pos, size_type __n1, const value_type* __s);
+ replace(size_type __pos, size_type __n1, const value_type* __s, size_type __n2)
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n2 != 0 && __s == nullptr, " if n2 is not zero");
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string&
+ replace(size_type __pos, size_type __n1, const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s);
_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& replace(size_type __pos, size_type __n1, size_type __n2, value_type __c);
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string&
@@ -1783,7 +1790,8 @@ public:
return std::__str_find<value_type, size_type, traits_type, npos>(data(), size(), __sv.data(), __pos, __sv.size());
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::find(): received nullptr");
return std::__str_find<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
@@ -1814,7 +1822,8 @@ public:
return std::__str_rfind<value_type, size_type, traits_type, npos>(data(), size(), __sv.data(), __pos, __sv.size());
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type rfind(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type rfind(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::rfind(): received nullptr");
return std::__str_rfind<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
@@ -1847,7 +1856,8 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 size_type
- find_first_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ find_first_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::find_first_of(): received nullptr");
return std::__str_find_first_of<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
@@ -1881,7 +1891,8 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 size_type
- find_last_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ find_last_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::find_last_of(): received nullptr");
return std::__str_find_last_of<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
@@ -1915,7 +1926,8 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 size_type
- find_first_not_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ find_first_not_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::find_first_not_of(): received nullptr");
return std::__str_find_first_not_of<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
@@ -1949,7 +1961,8 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 size_type
- find_last_not_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ find_last_not_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::find_last_not_of(): received nullptr");
return std::__str_find_last_not_of<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
@@ -2026,7 +2039,8 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 int
- compare(size_type __pos1, size_type __n1, const value_type* __s, size_type __n2) const;
+ compare(size_type __pos1, size_type __n1, const value_type* __s, size_type __n2) const
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n2 != 0 && __s == nullptr, " if n2 is not zero");
// starts_with
@@ -3564,7 +3578,8 @@ operator==(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
template <class _CharT, class _Traits, class _Allocator>
inline _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool
-operator==(const basic_string<_CharT, _Traits, _Allocator>& __lhs, const _CharT* __rhs) _NOEXCEPT {
+operator==(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
+ const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __rhs) _NOEXCEPT {
_LIBCPP_ASSERT_NON_NULL(__rhs != nullptr, "operator==(basic_string, char*): received nullptr");
using _String = basic_string<_CharT, _Traits, _Allocator>;
diff --git a/libcxx/include/string_view b/libcxx/include/string_view
index 861187c..f86b272 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -318,8 +318,8 @@ public:
_LIBCPP_HIDE_FROM_ABI basic_string_view& operator=(const basic_string_view&) _NOEXCEPT = default;
_LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI basic_string_view(const _CharT* __s, size_type __len) _NOEXCEPT
- : __data_(__s),
- __size_(__len) {
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__len != 0 && __s == nullptr, " if len is not zero")
+ : __data_(__s), __size_(__len) {
# if _LIBCPP_STD_VER >= 14
// Allocations must fit in `ptrdiff_t` for pointer arithmetic to work. If `__len` exceeds it, the input
// range could not have been valid. Most likely the caller underflowed some arithmetic and inadvertently
@@ -352,7 +352,7 @@ public:
: __data_(ranges::data(__r)), __size_(ranges::size(__r)) {}
# endif // _LIBCPP_STD_VER >= 23
- _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI basic_string_view(const _CharT* __s)
+ _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI basic_string_view(const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __s)
: __data_(__s), __size_(std::__char_traits_length_checked<_Traits>(__s)) {}
# if _LIBCPP_STD_VER >= 23
@@ -483,17 +483,19 @@ public:
return substr(__pos1, __n1).compare(__sv.substr(__pos2, __n2));
}
- _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI int compare(const _CharT* __s) const _NOEXCEPT {
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI int
+ compare(const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __s) const _NOEXCEPT {
return compare(basic_string_view(__s));
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI int
- compare(size_type __pos1, size_type __n1, const _CharT* __s) const {
+ compare(size_type __pos1, size_type __n1, const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __s) const {
return substr(__pos1, __n1).compare(basic_string_view(__s));
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI int
- compare(size_type __pos1, size_type __n1, const _CharT* __s, size_type __n2) const {
+ compare(size_type __pos1, size_type __n1, const _CharT* __s, size_type __n2) const
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n2 != 0 && __s == nullptr, " if n2 is not zero") {
return substr(__pos1, __n1).compare(basic_string_view(__s, __n2));
}
@@ -509,13 +511,14 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- find(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ find(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string_view::find(): received nullptr");
return std::__str_find<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- find(const _CharT* __s, size_type __pos = 0) const _NOEXCEPT {
+ find(const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = 0) const _NOEXCEPT {
_LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string_view::find(): received nullptr");
return std::__str_find<value_type, size_type, traits_type, npos>(
data(), size(), __s, __pos, traits_type::length(__s));
@@ -534,13 +537,14 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- rfind(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ rfind(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string_view::rfind(): received nullptr");
return std::__str_rfind<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- rfind(const _CharT* __s, size_type __pos = npos) const _NOEXCEPT {
+ rfind(const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = npos) const _NOEXCEPT {
_LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string_view::rfind(): received nullptr");
return std::__str_rfind<value_type, size_type, traits_type, npos>(
data(), size(), __s, __pos, traits_type::length(__s));
@@ -560,13 +564,14 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- find_first_of(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ find_first_of(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string_view::find_first_of(): received nullptr");
return std::__str_find_first_of<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- find_first_of(const _CharT* __s, size_type __pos = 0) const _NOEXCEPT {
+ find_first_of(const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = 0) const _NOEXCEPT {
_LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string_view::find_first_of(): received nullptr");
return std::__str_find_first_of<value_type, size_type, traits_type, npos>(
data(), size(), __s, __pos, traits_type::length(__s));
@@ -586,13 +591,14 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- find_last_of(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ find_last_of(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string_view::find_last_of(): received nullptr");
return std::__str_find_last_of<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- find_last_of(const _CharT* __s, size_type __pos = npos) const _NOEXCEPT {
+ find_last_of(const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = npos) const _NOEXCEPT {
_LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string_view::find_last_of(): received nullptr");
return std::__str_find_last_of<value_type, size_type, traits_type, npos>(
data(), size(), __s, __pos, traits_type::length(__s));
@@ -613,13 +619,14 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- find_first_not_of(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ find_first_not_of(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string_view::find_first_not_of(): received nullptr");
return std::__str_find_first_not_of<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- find_first_not_of(const _CharT* __s, size_type __pos = 0) const _NOEXCEPT {
+ find_first_not_of(const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = 0) const _NOEXCEPT {
_LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string_view::find_first_not_of(): received nullptr");
return std::__str_find_first_not_of<value_type, size_type, traits_type, npos>(
data(), size(), __s, __pos, traits_type::length(__s));
@@ -640,13 +647,14 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- find_last_not_of(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT {
+ find_last_not_of(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT
+ _LIBCPP_DIAGNOSE_NULLPTR_IF(__n != 0 && __s == nullptr, " if n is not zero") {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string_view::find_last_not_of(): received nullptr");
return std::__str_find_last_not_of<value_type, size_type, traits_type, npos>(data(), size(), __s, __pos, __n);
}
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type
- find_last_not_of(const _CharT* __s, size_type __pos = npos) const _NOEXCEPT {
+ find_last_not_of(const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = npos) const _NOEXCEPT {
_LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string_view::find_last_not_of(): received nullptr");
return std::__str_find_last_not_of<value_type, size_type, traits_type, npos>(
data(), size(), __s, __pos, traits_type::length(__s));
@@ -661,7 +669,7 @@ public:
return !empty() && _Traits::eq(front(), __c);
}
- constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(const value_type* __s) const noexcept {
+ constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const noexcept {
return starts_with(basic_string_view(__s));
}
@@ -673,7 +681,7 @@ public:
return !empty() && _Traits::eq(back(), __c);
}
- constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(const value_type* __s) const noexcept {
+ constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const noexcept {
return ends_with(basic_string_view(__s));
}
# endif
@@ -683,7 +691,9 @@ public:
constexpr _LIBCPP_HIDE_FROM_ABI bool contains(value_type __c) const noexcept { return find(__c) != npos; }
- constexpr _LIBCPP_HIDE_FROM_ABI bool contains(const value_type* __s) const { return find(__s) != npos; }
+ constexpr _LIBCPP_HIDE_FROM_ABI bool contains(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const {
+ return find(__s) != npos;
+ }
# endif
private:
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 75021f0..1623702 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -229,7 +229,6 @@ template <class... Types>
# include <__tuple/make_tuple_types.h>
# include <__tuple/sfinae_helpers.h>
# include <__tuple/tuple_element.h>
-# include <__tuple/tuple_indices.h>
# include <__tuple/tuple_like_ext.h>
# include <__tuple/tuple_size.h>
# include <__tuple/tuple_types.h>
@@ -444,12 +443,6 @@ public:
template <class... _Tp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __swallow(_Tp&&...) _NOEXCEPT {}
-template <class _Tp>
-struct __all_default_constructible;
-
-template <class... _Tp>
-struct __all_default_constructible<__tuple_types<_Tp...>> : __all<is_default_constructible<_Tp>::value...> {};
-
// __tuple_impl
template <class _Indx, class... _Tp>
@@ -457,15 +450,15 @@ struct __tuple_impl;
template <size_t... _Indx, class... _Tp>
struct _LIBCPP_DECLSPEC_EMPTY_BASES
- __tuple_impl<__tuple_indices<_Indx...>, _Tp...> : public __tuple_leaf<_Indx, _Tp>... {
+ __tuple_impl<__index_sequence<_Indx...>, _Tp...> : public __tuple_leaf<_Indx, _Tp>... {
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_impl() noexcept(
__all<is_nothrow_default_constructible<_Tp>::value...>::value) {}
template <size_t... _Uf, class... _Tf, size_t... _Ul, class... _Tl, class... _Up>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_impl(
- __tuple_indices<_Uf...>,
+ __index_sequence<_Uf...>,
__tuple_types<_Tf...>,
- __tuple_indices<_Ul...>,
+ __index_sequence<_Ul...>,
__tuple_types<_Tl...>,
_Up&&... __u) noexcept(__all<is_nothrow_constructible<_Tf, _Up>::value...>::value &&
__all<is_nothrow_default_constructible<_Tl>::value...>::value)
@@ -475,9 +468,9 @@ struct _LIBCPP_DECLSPEC_EMPTY_BASES
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_impl(
allocator_arg_t,
const _Alloc& __a,
- __tuple_indices<_Uf...>,
+ __index_sequence<_Uf...>,
__tuple_types<_Tf...>,
- __tuple_indices<_Ul...>,
+ __index_sequence<_Ul...>,
__tuple_types<_Tl...>,
_Up&&... __u)
: __tuple_leaf<_Uf, _Tf>(__uses_alloc_ctor<_Tf, _Alloc, _Up>(), __a, std::forward<_Up>(__u))...,
@@ -518,19 +511,19 @@ struct _LIBCPP_DECLSPEC_EMPTY_BASES
template <class _Dest, class _Source, size_t... _Np>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
-__memberwise_copy_assign(_Dest& __dest, _Source const& __source, __tuple_indices<_Np...>) {
+__memberwise_copy_assign(_Dest& __dest, _Source const& __source, __index_sequence<_Np...>) {
std::__swallow(((std::get<_Np>(__dest) = std::get<_Np>(__source)), void(), 0)...);
}
template <class _Dest, class _Source, class... _Up, size_t... _Np>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
-__memberwise_forward_assign(_Dest& __dest, _Source&& __source, __tuple_types<_Up...>, __tuple_indices<_Np...>) {
+__memberwise_forward_assign(_Dest& __dest, _Source&& __source, __tuple_types<_Up...>, __index_sequence<_Np...>) {
std::__swallow(((std::get<_Np>(__dest) = std::forward<_Up>(std::get<_Np>(__source))), void(), 0)...);
}
template <class... _Tp>
class _LIBCPP_NO_SPECIALIZATIONS tuple {
- typedef __tuple_impl<typename __make_tuple_indices<sizeof...(_Tp)>::type, _Tp...> _BaseT;
+ typedef __tuple_impl<__make_index_sequence<sizeof...(_Tp)>, _Tp...> _BaseT;
_BaseT __base_;
@@ -568,9 +561,9 @@ public:
tuple(allocator_arg_t, _Alloc const& __a)
: __base_(allocator_arg_t(),
__a,
- __tuple_indices<>(),
+ __index_sequence<>(),
__tuple_types<>(),
- typename __make_tuple_indices<sizeof...(_Tp), 0>::type(),
+ __make_index_sequence<sizeof...(_Tp)>(),
__tuple_types<_Tp...>()) {}
// tuple(const T&...) constructors (including allocator_arg_t variants)
@@ -579,10 +572,10 @@ public:
_LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_Lazy<_And, is_convertible<const _Tp&, _Tp>...> >::value)
tuple(const _Tp&... __t) noexcept(_And<is_nothrow_copy_constructible<_Tp>...>::value)
- : __base_(typename __make_tuple_indices<sizeof...(_Tp)>::type(),
- typename __make_tuple_types<tuple, sizeof...(_Tp)>::type(),
- typename __make_tuple_indices<0>::type(),
- typename __make_tuple_types<tuple, 0>::type(),
+ : __base_(__make_index_sequence<sizeof...(_Tp)>(),
+ __tuple_types<_Tp...>(),
+ __index_sequence<>(),
+ __tuple_types<>(),
__t...) {}
template <class _Alloc,
@@ -593,10 +586,10 @@ public:
tuple(allocator_arg_t, const _Alloc& __a, const _Tp&... __t)
: __base_(allocator_arg_t(),
__a,
- typename __make_tuple_indices<sizeof...(_Tp)>::type(),
- typename __make_tuple_types<tuple, sizeof...(_Tp)>::type(),
- typename __make_tuple_indices<0>::type(),
- typename __make_tuple_types<tuple, 0>::type(),
+ __make_index_sequence<sizeof...(_Tp)>(),
+ __tuple_types<_Tp...>(),
+ __index_sequence<>(),
+ __tuple_types<>(),
__t...) {}
// tuple(U&& ...) constructors (including allocator_arg_t variants)
@@ -616,10 +609,10 @@ public:
int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_Lazy<_And, is_convertible<_Up, _Tp>...> >::value)
tuple(_Up&&... __u) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value)
- : __base_(typename __make_tuple_indices<sizeof...(_Up)>::type(),
- typename __make_tuple_types<tuple, sizeof...(_Up)>::type(),
- typename __make_tuple_indices<sizeof...(_Tp), sizeof...(_Up)>::type(),
- typename __make_tuple_types<tuple, sizeof...(_Tp), sizeof...(_Up)>::type(),
+ : __base_(__make_index_sequence<sizeof...(_Up)>(),
+ __tuple_types<_Tp...>(),
+ __index_sequence<>(),
+ __tuple_types<>(),
std::forward<_Up>(__u)...) {}
template <class _Alloc,
@@ -630,10 +623,10 @@ public:
tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
: __base_(allocator_arg_t(),
__a,
- typename __make_tuple_indices<sizeof...(_Up)>::type(),
- typename __make_tuple_types<tuple, sizeof...(_Up)>::type(),
- typename __make_tuple_indices<sizeof...(_Tp), sizeof...(_Up)>::type(),
- typename __make_tuple_types<tuple, sizeof...(_Tp), sizeof...(_Up)>::type(),
+ __make_index_sequence<sizeof...(_Up)>(),
+ __tuple_types<_Tp...>(),
+ __index_sequence<>(),
+ __tuple_types<>(),
std::forward<_Up>(__u)...) {}
// Copy and move constructors (including the allocator_arg_t variants)
@@ -838,7 +831,7 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 tuple&
operator=(_If<_And<is_copy_assignable<_Tp>...>::value, tuple, __nat> const& __tuple) noexcept(
_And<is_nothrow_copy_assignable<_Tp>...>::value) {
- std::__memberwise_copy_assign(*this, __tuple, typename __make_tuple_indices<sizeof...(_Tp)>::type());
+ std::__memberwise_copy_assign(*this, __tuple, __make_index_sequence<sizeof...(_Tp)>());
return *this;
}
@@ -846,7 +839,7 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr const tuple& operator=(tuple const& __tuple) const
requires(_And<is_copy_assignable<const _Tp>...>::value)
{
- std::__memberwise_copy_assign(*this, __tuple, typename __make_tuple_indices<sizeof...(_Tp)>::type());
+ std::__memberwise_copy_assign(*this, __tuple, __make_index_sequence<sizeof...(_Tp)>());
return *this;
}
@@ -854,7 +847,7 @@ public:
requires(_And<is_assignable<const _Tp&, _Tp>...>::value)
{
std::__memberwise_forward_assign(
- *this, std::move(__tuple), __tuple_types<_Tp...>(), typename __make_tuple_indices<sizeof...(_Tp)>::type());
+ *this, std::move(__tuple), __tuple_types<_Tp...>(), __make_index_sequence<sizeof...(_Tp)>());
return *this;
}
# endif // _LIBCPP_STD_VER >= 23
@@ -863,7 +856,7 @@ public:
operator=(_If<_And<is_move_assignable<_Tp>...>::value, tuple, __nat>&& __tuple) noexcept(
_And<is_nothrow_move_assignable<_Tp>...>::value) {
std::__memberwise_forward_assign(
- *this, std::move(__tuple), __tuple_types<_Tp...>(), typename __make_tuple_indices<sizeof...(_Tp)>::type());
+ *this, std::move(__tuple), __tuple_types<_Tp...>(), __make_index_sequence<sizeof...(_Tp)>());
return *this;
}
@@ -873,7 +866,7 @@ public:
int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 tuple&
operator=(tuple<_Up...> const& __tuple) noexcept(_And<is_nothrow_assignable<_Tp&, _Up const&>...>::value) {
- std::__memberwise_copy_assign(*this, __tuple, typename __make_tuple_indices<sizeof...(_Tp)>::type());
+ std::__memberwise_copy_assign(*this, __tuple, __make_index_sequence<sizeof...(_Tp)>());
return *this;
}
@@ -883,7 +876,7 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 tuple&
operator=(tuple<_Up...>&& __tuple) noexcept(_And<is_nothrow_assignable<_Tp&, _Up>...>::value) {
std::__memberwise_forward_assign(
- *this, std::move(__tuple), __tuple_types<_Up...>(), typename __make_tuple_indices<sizeof...(_Tp)>::type());
+ *this, std::move(__tuple), __tuple_types<_Up...>(), __make_index_sequence<sizeof...(_Tp)>());
return *this;
}
@@ -892,7 +885,7 @@ public:
enable_if_t< _And<_BoolConstant<sizeof...(_Tp) == sizeof...(_UTypes)>,
is_assignable<const _Tp&, const _UTypes&>...>::value>* = nullptr>
_LIBCPP_HIDE_FROM_ABI constexpr const tuple& operator=(const tuple<_UTypes...>& __u) const {
- std::__memberwise_copy_assign(*this, __u, typename __make_tuple_indices<sizeof...(_Tp)>::type());
+ std::__memberwise_copy_assign(*this, __u, __make_index_sequence<sizeof...(_Tp)>());
return *this;
}
@@ -900,8 +893,7 @@ public:
enable_if_t< _And<_BoolConstant<sizeof...(_Tp) == sizeof...(_UTypes)>,
is_assignable<const _Tp&, _UTypes>...>::value>* = nullptr>
_LIBCPP_HIDE_FROM_ABI constexpr const tuple& operator=(tuple<_UTypes...>&& __u) const {
- std::__memberwise_forward_assign(
- *this, __u, __tuple_types<_UTypes...>(), typename __make_tuple_indices<sizeof...(_Tp)>::type());
+ std::__memberwise_forward_assign(*this, __u, __tuple_types<_UTypes...>(), __make_index_sequence<sizeof...(_Tp)>());
return *this;
}
# endif // _LIBCPP_STD_VER >= 23
@@ -967,7 +959,7 @@ public:
__enable_if_t< _And< _BoolConstant<_Np == sizeof...(_Tp)>, is_assignable<_Tp&, _Up const&>... >::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 tuple&
operator=(array<_Up, _Np> const& __array) noexcept(_And<is_nothrow_assignable<_Tp&, _Up const&>...>::value) {
- std::__memberwise_copy_assign(*this, __array, typename __make_tuple_indices<sizeof...(_Tp)>::type());
+ std::__memberwise_copy_assign(*this, __array, __make_index_sequence<sizeof...(_Tp)>());
return *this;
}
@@ -979,10 +971,7 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 tuple&
operator=(array<_Up, _Np>&& __array) noexcept(_And<is_nothrow_assignable<_Tp&, _Up>...>::value) {
std::__memberwise_forward_assign(
- *this,
- std::move(__array),
- __tuple_types<_If<true, _Up, _Tp>...>(),
- typename __make_tuple_indices<sizeof...(_Tp)>::type());
+ *this, std::move(__array), __tuple_types<_If<true, _Up, _Tp>...>(), __make_index_sequence<sizeof...(_Tp)>());
return *this;
}
@@ -1291,17 +1280,17 @@ template <class _Rp, class _Indices, class _Tuple0, class... _Tuples>
struct __tuple_cat_return_ref_imp;
template <class... _Types, size_t... _I0, class _Tuple0>
-struct __tuple_cat_return_ref_imp<tuple<_Types...>, __tuple_indices<_I0...>, _Tuple0> {
+struct __tuple_cat_return_ref_imp<tuple<_Types...>, __index_sequence<_I0...>, _Tuple0> {
using _T0 _LIBCPP_NODEBUG = __libcpp_remove_reference_t<_Tuple0>;
typedef tuple<_Types..., __copy_cvref_t<_Tuple0, typename tuple_element<_I0, _T0>::type>&&...> type;
};
template <class... _Types, size_t... _I0, class _Tuple0, class _Tuple1, class... _Tuples>
-struct __tuple_cat_return_ref_imp<tuple<_Types...>, __tuple_indices<_I0...>, _Tuple0, _Tuple1, _Tuples...>
+struct __tuple_cat_return_ref_imp<tuple<_Types...>, __index_sequence<_I0...>, _Tuple0, _Tuple1, _Tuples...>
: public __tuple_cat_return_ref_imp<
tuple<_Types...,
__copy_cvref_t<_Tuple0, typename tuple_element<_I0, __libcpp_remove_reference_t<_Tuple0>>::type>&&...>,
- typename __make_tuple_indices<tuple_size<__libcpp_remove_reference_t<_Tuple1> >::value>::type,
+ __make_index_sequence<tuple_size<__libcpp_remove_reference_t<_Tuple1> >::value>,
_Tuple1,
_Tuples...> {};
@@ -1309,7 +1298,7 @@ template <class _Tuple0, class... _Tuples>
struct __tuple_cat_return_ref
: public __tuple_cat_return_ref_imp<
tuple<>,
- typename __make_tuple_indices< tuple_size<__libcpp_remove_reference_t<_Tuple0> >::value >::type,
+ __make_index_sequence< tuple_size<__libcpp_remove_reference_t<_Tuple0> >::value >,
_Tuple0,
_Tuples...> {};
@@ -1317,7 +1306,7 @@ template <class _Types, class _I0, class _J0>
struct __tuple_cat;
template <class... _Types, size_t... _I0, size_t... _J0>
-struct __tuple_cat<tuple<_Types...>, __tuple_indices<_I0...>, __tuple_indices<_J0...> > {
+struct __tuple_cat<tuple<_Types...>, __index_sequence<_I0...>, __index_sequence<_J0...>> {
template <class _Tuple0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
typename __tuple_cat_return_ref<tuple<_Types...>&&, _Tuple0&&>::type
@@ -1335,8 +1324,8 @@ struct __tuple_cat<tuple<_Types...>, __tuple_indices<_I0...>, __tuple_indices<_J
using _T0 _LIBCPP_NODEBUG = __libcpp_remove_reference_t<_Tuple0>;
using _T1 _LIBCPP_NODEBUG = __libcpp_remove_reference_t<_Tuple1>;
return __tuple_cat<tuple<_Types..., __copy_cvref_t<_Tuple0, typename tuple_element<_J0, _T0>::type>&&...>,
- typename __make_tuple_indices<sizeof...(_Types) + tuple_size<_T0>::value>::type,
- typename __make_tuple_indices<tuple_size<_T1>::value>::type>()(
+ __make_index_sequence<sizeof...(_Types) + tuple_size<_T0>::value>,
+ __make_index_sequence<tuple_size<_T1>::value>>()(
std::forward_as_tuple(
std::forward<_Types>(std::get<_I0>(__t))..., std::get<_J0>(std::forward<_Tuple0>(__t0))...),
std::forward<_Tuple1>(__t1),
@@ -1346,7 +1335,7 @@ struct __tuple_cat<tuple<_Types...>, __tuple_indices<_I0...>, __tuple_indices<_J
template <class _TupleDst, class _TupleSrc, size_t... _Indices>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _TupleDst
-__tuple_cat_select_element_wise(_TupleSrc&& __src, __tuple_indices<_Indices...>) {
+__tuple_cat_select_element_wise(_TupleSrc&& __src, __index_sequence<_Indices...>) {
static_assert(tuple_size<_TupleDst>::value == tuple_size<_TupleSrc>::value,
"misuse of __tuple_cat_select_element_wise with tuples of different sizes");
return _TupleDst(std::get<_Indices>(std::forward<_TupleSrc>(__src))...);
@@ -1357,10 +1346,10 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __tuple_cat_
tuple_cat(_Tuple0&& __t0, _Tuples&&... __tpls) {
using _T0 _LIBCPP_NODEBUG = __libcpp_remove_reference_t<_Tuple0>;
using _TRet _LIBCPP_NODEBUG = typename __tuple_cat_return<_Tuple0, _Tuples...>::type;
- using _T0Indices _LIBCPP_NODEBUG = typename __make_tuple_indices<tuple_size<_T0>::value>::type;
- using _TRetIndices _LIBCPP_NODEBUG = typename __make_tuple_indices<tuple_size<_TRet>::value>::type;
+ using _T0Indices _LIBCPP_NODEBUG = __make_index_sequence<tuple_size<_T0>::value>;
+ using _TRetIndices _LIBCPP_NODEBUG = __make_index_sequence<tuple_size<_TRet>::value>;
return std::__tuple_cat_select_element_wise<_TRet>(
- __tuple_cat<tuple<>, __tuple_indices<>, _T0Indices>()(
+ __tuple_cat<tuple<>, __index_sequence<>, _T0Indices>()(
tuple<>(), std::forward<_Tuple0>(__t0), std::forward<_Tuples>(__tpls)...),
_TRetIndices());
}
@@ -1376,7 +1365,7 @@ struct uses_allocator<tuple<_Tp...>, _Alloc> : true_type {};
// clang-format off
template <class _Fn, class _Tuple, size_t... _Id>
inline _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto)
-__apply_tuple_impl(_Fn&& __f, _Tuple&& __t, __tuple_indices<_Id...>)
+__apply_tuple_impl(_Fn&& __f, _Tuple&& __t, index_sequence<_Id...>)
_LIBCPP_NOEXCEPT_RETURN(std::__invoke(std::forward<_Fn>(__f), std::get<_Id>(std::forward<_Tuple>(__t))...))
template <class _Fn, class _Tuple>
@@ -1384,28 +1373,28 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) apply(_Fn&& __f, _Tuple&&
_LIBCPP_NOEXCEPT_RETURN(std::__apply_tuple_impl(
std::forward<_Fn>(__f),
std::forward<_Tuple>(__t),
- typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type{}))
+ make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>()))
#if _LIBCPP_STD_VER >= 20
template <class _Tp, class _Tuple, size_t... _Idx>
-inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>)
+inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>)
noexcept(noexcept(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...)))
requires is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...> {
return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...);
}
#else
template <class _Tp, class _Tuple, size_t... _Idx>
-inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>,
+inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>,
enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>> * = nullptr)
_LIBCPP_NOEXCEPT_RETURN(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...))
#endif // _LIBCPP_STD_VER >= 20
template <class _Tp, class _Tuple,
- class _Seq = typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type, class = void>
+ class _Seq = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>, class = void>
inline constexpr bool __can_make_from_tuple = false;
template <class _Tp, class _Tuple, size_t... _Idx>
-inline constexpr bool __can_make_from_tuple<_Tp, _Tuple, __tuple_indices<_Idx...>,
+inline constexpr bool __can_make_from_tuple<_Tp, _Tuple, index_sequence<_Idx...>,
enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::declval<_Tuple>()))...>>> = true;
// Based on LWG3528(https://wg21.link/LWG3528) and http://eel.is/c++draft/description#structure.requirements-9,
@@ -1420,7 +1409,7 @@ template <class _Tp, class _Tuple, class = enable_if_t<__can_make_from_tuple<_Tp
#endif // _LIBCPP_STD_VER >= 20
inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp make_from_tuple(_Tuple&& __t)
_LIBCPP_NOEXCEPT_RETURN(std::__make_from_tuple_impl<_Tp>(
- std::forward<_Tuple>(__t), typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type{}))
+ std::forward<_Tuple>(__t), make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>()))
# undef _LIBCPP_NOEXCEPT_RETURN
# endif // _LIBCPP_STD_VER >= 17
diff --git a/libcxx/include/variant b/libcxx/include/variant
index ede9f48..9beef14 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1127,14 +1127,14 @@ template <class _IdxSeq>
struct __make_overloads_imp;
template <size_t... _Idx>
-struct __make_overloads_imp<__tuple_indices<_Idx...> > {
+struct __make_overloads_imp<index_sequence<_Idx...> > {
template <class... _Types>
using _Apply _LIBCPP_NODEBUG = __all_overloads<__overload<_Types, _Idx>...>;
};
template <class... _Types>
using _MakeOverloads _LIBCPP_NODEBUG =
- typename __make_overloads_imp< __make_indices_imp<sizeof...(_Types), 0> >::template _Apply<_Types...>;
+ typename __make_overloads_imp<make_index_sequence<sizeof...(_Types)>>::template _Apply<_Types...>;
template <class _Tp, class... _Types>
using __best_match_t _LIBCPP_NODEBUG = typename invoke_result_t<_MakeOverloads<_Types...>, _Tp, _Tp>::type;
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index adabeeb..7ede42e 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -289,16 +289,16 @@ export namespace std {
namespace views {
using std::ranges::views::zip;
} // namespace views
-#endif // _LIBCPP_STD_VER >= 23
-#if 0
// [range.zip.transform], zip transform view
using std::ranges::zip_transform_view;
namespace views {
using std::ranges::views::zip_transform;
}
+#endif // _LIBCPP_STD_VER >= 23
+#if 0
using std::ranges::adjacent_view;
namespace views {
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index 97fe57a..f59fe0e 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -309,6 +309,7 @@ add_custom_target(cxx DEPENDS ${LIBCXX_BUILD_TARGETS})
# Build the experimental static library
set(LIBCXX_EXPERIMENTAL_SOURCES
experimental/keep.cpp
+ experimental/log_hardening_failure.cpp
)
if (LIBCXX_PSTL_BACKEND STREQUAL "libdispatch")
diff --git a/libcxx/src/experimental/log_hardening_failure.cpp b/libcxx/src/experimental/log_hardening_failure.cpp
new file mode 100644
index 0000000..f836c15
--- /dev/null
+++ b/libcxx/src/experimental/log_hardening_failure.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache 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 <__config>
+#include <__log_hardening_failure>
+#include <cstdio>
+
+#ifdef __BIONIC__
+# include <syslog.h>
+#endif // __BIONIC__
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+void __log_hardening_failure(const char* message) noexcept {
+ // Always log the message to `stderr` in case the platform-specific system calls fail.
+ std::fputs(message, stderr);
+
+#if defined(__BIONIC__)
+ // Show error in logcat. The latter two arguments are ignored on Android.
+ openlog("libc++", 0, 0);
+ syslog(LOG_CRIT, "%s", message);
+ closelog();
+#endif
+}
+
+_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/libcxx/containers/gnu_cxx/hash_map.pass.cpp b/libcxx/test/extensions/gnu/hash_map/hash_map.pass.cpp
index a8988f7..a8988f7 100644
--- a/libcxx/test/libcxx/containers/gnu_cxx/hash_map.pass.cpp
+++ b/libcxx/test/extensions/gnu/hash_map/hash_map.pass.cpp
diff --git a/libcxx/test/libcxx/containers/gnu_cxx/hash_map_name_lookup.pass.cpp b/libcxx/test/extensions/gnu/hash_map/hash_map_name_lookup.pass.cpp
index 7e87330..7e87330 100644
--- a/libcxx/test/libcxx/containers/gnu_cxx/hash_map_name_lookup.pass.cpp
+++ b/libcxx/test/extensions/gnu/hash_map/hash_map_name_lookup.pass.cpp
diff --git a/libcxx/test/libcxx/containers/gnu_cxx/hash_set.pass.cpp b/libcxx/test/extensions/gnu/hash_set/hash_set.pass.cpp
index c325914..c325914 100644
--- a/libcxx/test/libcxx/containers/gnu_cxx/hash_set.pass.cpp
+++ b/libcxx/test/extensions/gnu/hash_set/hash_set.pass.cpp
diff --git a/libcxx/test/libcxx/containers/gnu_cxx/hash_set_name_lookup.pass.cpp b/libcxx/test/extensions/gnu/hash_set/hash_set_name_lookup.pass.cpp
index c5f64a4..c5f64a4 100644
--- a/libcxx/test/libcxx/containers/gnu_cxx/hash_set_name_lookup.pass.cpp
+++ b/libcxx/test/extensions/gnu/hash_set/hash_set_name_lookup.pass.cpp
diff --git a/libcxx/test/libcxx/atomics/atomics.flag/init_bool.pass.cpp b/libcxx/test/extensions/libcxx/atomics/atomics.flag/init_bool.pass.cpp
index 76787755..76787755 100644
--- a/libcxx/test/libcxx/atomics/atomics.flag/init_bool.pass.cpp
+++ b/libcxx/test/extensions/libcxx/atomics/atomics.flag/init_bool.pass.cpp
diff --git a/libcxx/test/libcxx/containers/associative/map/scary.compile.pass.cpp b/libcxx/test/extensions/libcxx/containers/associative/map/scary.compile.pass.cpp
index 89e753f..89e753f 100644
--- a/libcxx/test/libcxx/containers/associative/map/scary.compile.pass.cpp
+++ b/libcxx/test/extensions/libcxx/containers/associative/map/scary.compile.pass.cpp
diff --git a/libcxx/test/libcxx/containers/associative/set/scary.compile.pass.cpp b/libcxx/test/extensions/libcxx/containers/associative/set/scary.compile.pass.cpp
index 87ed05d..87ed05d 100644
--- a/libcxx/test/libcxx/containers/associative/set/scary.compile.pass.cpp
+++ b/libcxx/test/extensions/libcxx/containers/associative/set/scary.compile.pass.cpp
diff --git a/libcxx/test/libcxx/containers/associative/unord.map/scary.compile.pass.cpp b/libcxx/test/extensions/libcxx/containers/associative/unord.map/scary.compile.pass.cpp
index db2ef33..db2ef33 100644
--- a/libcxx/test/libcxx/containers/associative/unord.map/scary.compile.pass.cpp
+++ b/libcxx/test/extensions/libcxx/containers/associative/unord.map/scary.compile.pass.cpp
diff --git a/libcxx/test/libcxx/containers/associative/unord.set/scary.compile.pass.cpp b/libcxx/test/extensions/libcxx/containers/associative/unord.set/scary.compile.pass.cpp
index cd33e1a..cd33e1a 100644
--- a/libcxx/test/libcxx/containers/associative/unord.set/scary.compile.pass.cpp
+++ b/libcxx/test/extensions/libcxx/containers/associative/unord.set/scary.compile.pass.cpp
diff --git a/libcxx/test/libcxx/containers/sequences/deque/incomplete.pass.cpp b/libcxx/test/extensions/libcxx/containers/sequences/deque/incomplete.pass.cpp
index ebf5869..ebf5869 100644
--- a/libcxx/test/libcxx/containers/sequences/deque/incomplete.pass.cpp
+++ b/libcxx/test/extensions/libcxx/containers/sequences/deque/incomplete.pass.cpp
diff --git a/libcxx/test/libcxx/depr/depr.c.headers/extern_c.pass.cpp b/libcxx/test/extensions/libcxx/depr/depr.c.headers/extern_c.pass.cpp
index f756aac..f756aac 100644
--- a/libcxx/test/libcxx/depr/depr.c.headers/extern_c.pass.cpp
+++ b/libcxx/test/extensions/libcxx/depr/depr.c.headers/extern_c.pass.cpp
diff --git a/libcxx/test/extensions/libcxx/include_as_c.sh.cpp b/libcxx/test/extensions/libcxx/depr/depr.c.headers/include_as_c.sh.cpp
index 635c7e3..635c7e3 100644
--- a/libcxx/test/extensions/libcxx/include_as_c.sh.cpp
+++ b/libcxx/test/extensions/libcxx/depr/depr.c.headers/include_as_c.sh.cpp
diff --git a/libcxx/test/libcxx/depr/depr.c.headers/stdint_h.std_types_t.compile.pass.cpp b/libcxx/test/extensions/libcxx/depr/depr.c.headers/stdint_h.std_types_t.compile.pass.cpp
index 3485ce7..3485ce7 100644
--- a/libcxx/test/libcxx/depr/depr.c.headers/stdint_h.std_types_t.compile.pass.cpp
+++ b/libcxx/test/extensions/libcxx/depr/depr.c.headers/stdint_h.std_types_t.compile.pass.cpp
diff --git a/libcxx/test/libcxx/depr/depr.c.headers/stdint_h.xopen_source.compile.pass.cpp b/libcxx/test/extensions/libcxx/depr/depr.c.headers/stdint_h.xopen_source.compile.pass.cpp
index 75a4ab9..75a4ab9 100644
--- a/libcxx/test/libcxx/depr/depr.c.headers/stdint_h.xopen_source.compile.pass.cpp
+++ b/libcxx/test/extensions/libcxx/depr/depr.c.headers/stdint_h.xopen_source.compile.pass.cpp
diff --git a/libcxx/test/libcxx/depr/depr.c.headers/math_h.compile.pass.cpp b/libcxx/test/extensions/msvc/math_h.compile.pass.cpp
index 045745b..045745b 100644
--- a/libcxx/test/libcxx/depr/depr.c.headers/math_h.compile.pass.cpp
+++ b/libcxx/test/extensions/msvc/math_h.compile.pass.cpp
diff --git a/libcxx/test/libcxx/algorithms/specialized.algorithms/nonnull.verify.cpp b/libcxx/test/libcxx/algorithms/specialized.algorithms/nonnull.verify.cpp
new file mode 100644
index 0000000..4d720fb
--- /dev/null
+++ b/libcxx/test/libcxx/algorithms/specialized.algorithms/nonnull.verify.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// Ensure that APIs which take a pointer are diagnosing passing a nullptr to them
+
+#include <memory>
+
+#include "test_macros.h"
+
+void func() {
+ using Arr = int[1];
+ int* const np = nullptr;
+
+#if TEST_STD_VER >= 20
+ Arr* const np2 = nullptr;
+ std::construct_at(np); // expected-warning {{null passed}}
+ std::destroy_at(np2); // expected-warning {{null passed}}
+#endif
+
+ std::destroy_at(np); // expected-warning {{null passed}}
+}
diff --git a/libcxx/test/libcxx/assertions/log_hardening_failure.pass.cpp b/libcxx/test/libcxx/assertions/log_hardening_failure.pass.cpp
new file mode 100644
index 0000000..dda071b
--- /dev/null
+++ b/libcxx/test/libcxx/assertions/log_hardening_failure.pass.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
+//
+//===----------------------------------------------------------------------===//
+
+// Basic smoke test for `__log_hardening_failure`.
+//
+// UNSUPPORTED: c++03
+// UNSUPPORTED: libcpp-has-no-experimental-hardening-observe-semantic
+
+#include <__log_hardening_failure>
+
+#include "test_macros.h"
+
+ASSERT_NOEXCEPT(std::__log_hardening_failure(""));
+
+int main(int, char**) {
+ std::__log_hardening_failure("Some message");
+ // It's difficult to properly test platform-specific logging behavior of the function; just make sure it exists and
+ // can be called at runtime.
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp
index 7ae67d8..b050da4 100644
--- a/libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp
@@ -6,7 +6,9 @@
//
//===----------------------------------------------------------------------===//
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
#include <deque>
using DequeIterator = typename std::deque<int>::iterator;
-static_assert(std::__is_segmented_iterator<DequeIterator>::value, "");
+static_assert(std::__is_segmented_iterator_v<DequeIterator>, "");
diff --git a/libcxx/test/libcxx/containers/sequences/deque/spare_block_handling.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/spare_block_handling.pass.cpp
index 4fa4982..c5f152a 100644
--- a/libcxx/test/libcxx/containers/sequences/deque/spare_block_handling.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/deque/spare_block_handling.pass.cpp
@@ -38,10 +38,10 @@ static void print(const Deque& d) {
" : __back_spare() == %zu"
" : __capacity() == %zu"
" : bytes allocated == %zu\n",
- d.size(),
- d.__front_spare(),
- d.__back_spare(),
- d.__capacity(),
+ std::size_t(d.size()),
+ std::size_t(d.__front_spare()),
+ std::size_t(d.__back_spare()),
+ std::size_t(d.__capacity()),
malloc_allocator_base::outstanding_bytes);
}
diff --git a/libcxx/test/libcxx/containers/sequences/forwardlist/bool-conversion.pass.cpp b/libcxx/test/libcxx/containers/sequences/forwardlist/bool-conversion.pass.cpp
deleted file mode 100644
index 237b0f1..0000000
--- a/libcxx/test/libcxx/containers/sequences/forwardlist/bool-conversion.pass.cpp
+++ /dev/null
@@ -1,37 +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
-//
-//===----------------------------------------------------------------------===//
-
-// REQUIRES: std-at-least-c++20
-
-// <forward_list>
-
-// This test shows the effect of implementing `LWG4135`, before it this code
-// was ill-formed, as the predicate is not bool. `LWG4135` suggests that
-// std::erase explicitly specifying the lambda's return type as bool.
-
-#include <forward_list>
-
-struct Bool {
- Bool() = default;
- Bool(const Bool&) = delete;
- operator bool() const { return true; }
-};
-
-struct Int {
- Bool& operator==(Int) const {
- static Bool b;
- return b;
- }
-};
-
-int main(int, char**) {
- std::forward_list<Int> l;
- std::erase(l, Int{});
-
- return 0;
-}
diff --git a/libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp
deleted file mode 100644
index 9e3fb88..0000000
--- a/libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp
+++ /dev/null
@@ -1,56 +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
-//
-//===----------------------------------------------------------------------===//
-
-// <vector>
-
-// template <class InputIter> vector(InputIter first, InputIter last);
-
-#include <vector>
-#include <cassert>
-
-#include "test_macros.h"
-#include "min_allocator.h"
-
-void test_ctor_under_alloc() {
- int arr1[] = {42};
- int arr2[] = {1, 101, 42};
- {
- typedef std::vector<int, cpp03_allocator<int> > C;
- typedef C::allocator_type Alloc;
- {
- Alloc::construct_called = false;
- C v(arr1, arr1 + 1);
- assert(Alloc::construct_called);
- }
- {
- Alloc::construct_called = false;
- C v(arr2, arr2 + 3);
- assert(Alloc::construct_called);
- }
- }
- {
- typedef std::vector<int, cpp03_overload_allocator<int> > C;
- typedef C::allocator_type Alloc;
- {
- Alloc::construct_called = false;
- C v(arr1, arr1 + 1);
- assert(Alloc::construct_called);
- }
- {
- Alloc::construct_called = false;
- C v(arr2, arr2 + 3);
- assert(Alloc::construct_called);
- }
- }
-}
-
-int main(int, char**) {
- test_ctor_under_alloc();
-
- return 0;
-}
diff --git a/libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
deleted file mode 100644
index fa1bd2d..0000000
--- a/libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
+++ /dev/null
@@ -1,59 +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
-//
-//===----------------------------------------------------------------------===//
-
-// <vector>
-
-// template <class InputIter> vector(InputIter first, InputIter last,
-// const allocator_type& a);
-
-#include <vector>
-#include <cassert>
-
-#include "test_macros.h"
-#include "min_allocator.h"
-
-void test_ctor_under_alloc() {
- int arr1[] = {42};
- int arr2[] = {1, 101, 42};
- {
- typedef std::vector<int, cpp03_allocator<int> > C;
- typedef C::allocator_type Alloc;
- Alloc a;
- {
- Alloc::construct_called = false;
- C v(arr1, arr1 + 1, a);
- assert(Alloc::construct_called);
- }
- {
- Alloc::construct_called = false;
- C v(arr2, arr2 + 3, a);
- assert(Alloc::construct_called);
- }
- }
- {
- typedef std::vector<int, cpp03_overload_allocator<int> > C;
- typedef C::allocator_type Alloc;
- Alloc a;
- {
- Alloc::construct_called = false;
- C v(arr1, arr1 + 1, a);
- assert(Alloc::construct_called);
- }
- {
- Alloc::construct_called = false;
- C v(arr2, arr2 + 3, a);
- assert(Alloc::construct_called);
- }
- }
-}
-
-int main(int, char**) {
- test_ctor_under_alloc();
-
- return 0;
-}
diff --git a/libcxx/test/libcxx/diagnostics/vector.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/vector.nodiscard.verify.cpp
index 51e90af..a5cad1a 100644
--- a/libcxx/test/libcxx/diagnostics/vector.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/vector.nodiscard.verify.cpp
@@ -10,14 +10,45 @@
// check that <vector> functions are marked [[nodiscard]]
+#include <type_traits>
#include <vector>
-void test_vector() {
- std::vector<int> vector;
- vector.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+template <class VecT>
+void test() {
+ VecT v;
+
+ v.at(0); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.back(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.begin(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.capacity(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.cbegin(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.cend(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.crbegin(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.crend(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.empty(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.end(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.front(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.get_allocator(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.max_size(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.rbegin(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.rend(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.size(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v[0]; // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}}
}
-void test_vector_bool() {
- std::vector<bool> vector;
- vector.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+template <class VecT>
+void test_non_vector_bool() {
+ VecT v;
+
+ v.data(); // expected-warning 2 {{ignoring return value of function declared with 'nodiscard' attribute}}
+}
+
+void instantiate() {
+ test<std::vector<int>>();
+ test<const std::vector<int>>();
+ test<std::vector<bool>>();
+ test<const std::vector<bool>>();
+
+ test_non_vector_bool<std::vector<int>>();
+ test_non_vector_bool<const std::vector<int>>();
}
diff --git a/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp b/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp
index 3cf497d..3d97446 100644
--- a/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp
+++ b/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp
@@ -29,3 +29,7 @@
#if !_LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM
# error "-fexperimental-library should enable the syncstream header"
#endif
+
+#if !_LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC
+# error "-fexperimental-library should allow using the Hardening observe semantic"
+#endif
diff --git a/libcxx/test/libcxx/input.output/iostream.format/print.fun/nonnull.verify.cpp b/libcxx/test/libcxx/input.output/iostream.format/print.fun/nonnull.verify.cpp
new file mode 100644
index 0000000..afa0bca
--- /dev/null
+++ b/libcxx/test/libcxx/input.output/iostream.format/print.fun/nonnull.verify.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: libcpp-has-no-unicode
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// Ensure that APIs which take a FILE* are diagnosing passing a nullptr to them
+
+#include <print>
+
+void func() {
+ std::print(nullptr, ""); // expected-warning {{null passed}}
+ std::println(nullptr, ""); // expected-warning {{null passed}}
+ std::println(nullptr); // expected-warning {{null passed}}
+ std::vprint_unicode(nullptr, "", std::make_format_args()); // expected-warning {{null passed}}
+ std::vprint_nonunicode(nullptr, "", std::make_format_args()); // expected-warning {{null passed}}
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp
index 6cd17c2..4e4074f 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp
@@ -14,4 +14,4 @@
using JoinView = decltype(std::views::join(std::declval<std::vector<std::vector<int>>&>()));
using JoinIter = std::ranges::iterator_t<JoinView>;
-static_assert(std::__is_segmented_iterator<JoinIter>::value);
+static_assert(std::__is_segmented_iterator_v<JoinIter>);
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.zip.transform/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.zip.transform/no_unique_address.compile.pass.cpp
new file mode 100644
index 0000000..4b66862
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.zip.transform/no_unique_address.compile.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// XFAIL: msvc
+
+// This test ensures that we use `[[no_unique_address]]` in `zip_transform_view`.
+
+#include <ranges>
+
+struct View : std::ranges::view_base {
+ int* begin() const;
+ int* end() const;
+};
+
+struct Pred {
+ template <class... Args>
+ bool operator()(const Args&...) const;
+};
+
+template <class View>
+struct Test {
+ [[no_unique_address]] View view;
+ char c;
+};
+
+static_assert(sizeof(std::ranges::zip_transform_view<Pred, View>) == 1);
diff --git a/libcxx/test/libcxx/strings/basic.string/nonnull.verify.cpp b/libcxx/test/libcxx/strings/basic.string/nonnull.verify.cpp
index d618962..f428c49 100644
--- a/libcxx/test/libcxx/strings/basic.string/nonnull.verify.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/nonnull.verify.cpp
@@ -8,7 +8,10 @@
// UNSUPPORTED: c++03
-// Ensure that APIs which take a CharT* (and no size for it) are diagnosing passing a nullptr to them
+// Ensure that APIs which take a CharT* are diagnosing passing a nullptr to them
+
+// Clang 19 and AppleClang don't have diagnose_if with diagnostic flags
+// UNSUPPORTED: clang-19, apple-clang-17
#include <string>
@@ -20,6 +23,7 @@ void func() {
std::string str2(np, std::allocator<char>{}); // expected-warning {{null passed}}
str2 = np; // expected-warning {{null passed}}
str2 += np; // expected-warning {{null passed}}
+ str2.assign(np); // expected-warning {{null passed}}
str2.append(np); // expected-warning {{null passed}}
str2.insert(0, np); // expected-warning {{null passed}}
str2.find(np); // expected-warning {{null passed}}
@@ -30,6 +34,8 @@ void func() {
str2.find_last_not_of(np); // expected-warning {{null passed}}
str2.compare(np); // expected-warning {{null passed}}
str2.compare(0, 0, np); // expected-warning {{null passed}}
+ str2.replace(0, 0, np); // expected-warning {{null passed}}
+ (void)(str2 == np); // expected-warning {{null passed}}
#if TEST_STD_VER >= 20
str2.starts_with(np); // expected-warning {{null passed}}
@@ -38,4 +44,21 @@ void func() {
#if TEST_STD_VER >= 23
str2.contains(np); // expected-warning {{null passed}}
#endif
+
+ // clang-format off
+ // These diagnostics are issued via diagnose_if, so we want to check the full description
+ std::string str3(nullptr, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ std::string str4(nullptr, 1, std::allocator<char>{}); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str4.find(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str4.rfind(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str4.find_first_of(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str4.find_last_of(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str4.find_first_not_of(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str4.find_last_not_of(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str4.compare(0, 0, nullptr, 1); // expected-warning {{null passed to callee that requires a non-null argument if n2 is not zero}}
+ str4.assign(nullptr, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str4.append(nullptr, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str4.insert(0, nullptr, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str4.replace(0, 0, nullptr, 1); // expected-warning {{null passed to callee that requires a non-null argument if n2 is not zero}}
+ // clang-format on
}
diff --git a/libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp b/libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
index 1810ec1..f358b5e 100644
--- a/libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
+++ b/libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
@@ -14,6 +14,9 @@
// Construct a string_view from a null pointer
// constexpr basic_string_view( const CharT* s );
+// We're testing for assertions here, so let's not diagnose the misuses at compile time
+// ADDITIONAL_COMPILE_FLAGS: -Wno-nonnull
+
#include <string_view>
#include "check_assertion.h"
diff --git a/libcxx/test/libcxx/strings/string.view/nonnull.verify.cpp b/libcxx/test/libcxx/strings/string.view/nonnull.verify.cpp
new file mode 100644
index 0000000..316c982
--- /dev/null
+++ b/libcxx/test/libcxx/strings/string.view/nonnull.verify.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
+
+// Ensure that APIs which take a CharT* are diagnosing passing a nullptr to them
+
+// Clang 19 and AppleClang don't have diagnose_if with diagnostic flags
+// UNSUPPORTED: clang-19, apple-clang-17
+
+#include <string_view>
+
+#include "test_macros.h"
+
+void func() {
+ const char* const np = nullptr;
+ std::string_view str1(np); // expected-warning {{null passed}}
+ str1 = np; // expected-warning {{null passed}}
+ str1.find(np); // expected-warning {{null passed}}
+ str1.rfind(np); // expected-warning {{null passed}}
+ str1.find_first_of(np); // expected-warning {{null passed}}
+ str1.find_last_of(np); // expected-warning {{null passed}}
+ str1.find_first_not_of(np); // expected-warning {{null passed}}
+ str1.find_last_not_of(np); // expected-warning {{null passed}}
+ str1.compare(np); // expected-warning {{null passed}}
+ str1.compare(0, 0, np); // expected-warning {{null passed}}
+ (void)(str1 == np); // expected-warning {{null passed}}
+
+#if TEST_STD_VER >= 20
+ str1.starts_with(np); // expected-warning {{null passed}}
+ str1.ends_with(np); // expected-warning {{null passed}}
+#endif
+#if TEST_STD_VER >= 23
+ str1.contains(np); // expected-warning {{null passed}}
+#endif
+
+ // clang-format off
+ // These diagnostics are issued via diagnose_if, so we want to check the full description
+ std::string_view str2(nullptr, 1); // expected-warning {{null passed to callee that requires a non-null argument if len is not zero}}
+ str2.find(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str2.rfind(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str2.find_first_of(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str2.find_last_of(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str2.find_first_not_of(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str2.find_last_not_of(nullptr, 0, 1); // expected-warning {{null passed to callee that requires a non-null argument if n is not zero}}
+ str2.compare(0, 0, nullptr, 1); // expected-warning {{null passed to callee that requires a non-null argument if n2 is not zero}}
+ // clang-format on
+}
diff --git a/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp b/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp
index 419a603..2bc4648 100644
--- a/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp
+++ b/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp
@@ -8,6 +8,8 @@
// UNSUPPORTED: no-threads
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// Without the assertion, the test will most likely time out.
+// UNSUPPORTED: libcpp-assertion-semantic={{ignore|observe}}
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
diff --git a/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp b/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp
index e6167955..30d36b5f 100644
--- a/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp
+++ b/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp
@@ -18,6 +18,8 @@
// REQUIRES: has-unix-headers
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// Without the assertion, the test will most likely time out.
+// UNSUPPORTED: libcpp-assertion-semantic={{ignore|observe}}
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <latch>
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
index 6137409..25cc08a 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
@@ -6,10 +6,6 @@
//
//===----------------------------------------------------------------------===//
-// Clang-18 fixed some spurious clang diagnostics. Once clang-18 is the
-// minimum required version these obsolete tests can be removed.
-// TODO(LLVM-20) remove spurious clang diagnostic tests.
-
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// With clang-cl, some warnings have a 'which is a Microsoft extension' suffix
@@ -59,12 +55,12 @@ void test() {
{
std::expected<int, int> e;
e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-1 {{no matching constructor for initialization of{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
// expected-error-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}}}
e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-1 {{no matching constructor for initialization of{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
// expected-warning-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}, which is a Microsoft extension}}
}
@@ -73,27 +69,27 @@ void test() {
{
const std::expected<int, int> e;
e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-2 {{no matching constructor for initialization of{{.*}}}}
e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-2 {{no matching constructor for initialization of{{.*}}}}
}
// Test && overload
{
std::expected<int, int> e;
std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-2 {{no matching constructor for initialization of{{.*}}}}
std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-2 {{no matching constructor for initialization of{{.*}}}}
}
// Test const&& overload
{
const std::expected<int, int> e;
std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-2 {{no matching constructor for initialization of{{.*}}}}
std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-2 {{no matching constructor for initialization of{{.*}}}}
}
}
// clang-format on
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
index 16233cd..2dd3acd 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
@@ -6,10 +6,6 @@
//
//===----------------------------------------------------------------------===//
-// Clang-18 fixed some spurious clang diagnostics. Once clang-18 is the
-// minumum required version these obsolete tests can be removed.
-// TODO(LLVM-20) remove spurious clang diagnostic tests.
-
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// With clang-cl, some warnings have a 'which is a Microsoft extension' suffix
@@ -60,13 +56,13 @@ void test() {
{
std::expected<void, int> e;
e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-1 {{no matching constructor for initialization of{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
// expected-error-re@*:* 0-1 {{call to deleted constructor of {{.*}}}}
// expected-error-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}}}
e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-1 {{no matching constructor for initialization of{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
// expected-warning-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}, which is a Microsoft extension}}
}
@@ -75,9 +71,9 @@ void test() {
{
const std::expected<void, int> e;
e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-1 {{no matching constructor for initialization of{{.*}}}}
e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-1 {{no matching constructor for initialization of{{.*}}}}
// expected-error-re@*:* 0-1 {{call to deleted constructor of {{.*}}}}
}
@@ -85,18 +81,18 @@ void test() {
{
std::expected<void, int> e;
std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-1 {{no matching constructor for initialization of{{.*}}}}
std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-1 {{no matching constructor for initialization of{{.*}}}}
}
// Test const&& overload
{
const std::expected<void, int> e;
std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-1 {{no matching constructor for initialization of{{.*}}}}
std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
- // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+ // expected-error-re@*:* 0-1 {{no matching constructor for initialization of{{.*}}}}
}
}
// clang-format on
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
index b162c2d..1b42695 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -8,10 +8,6 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// XFAIL: !has-64-bit-atomics
-// Older versions of clang have a bug with atomic builtins affecting double and long double.
-// Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
-
// https://github.com/llvm/llvm-project/issues/72893
// XFAIL: target={{x86_64-.*}} && tsan
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
index 8784037..cac7352 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -8,10 +8,6 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// XFAIL: !has-64-bit-atomics
-// Older versions of clang have a bug with atomic builtins affecting double and long double.
-// Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
-
// https://github.com/llvm/llvm-project/issues/72893
// XFAIL: target={{x86_64-.*}} && tsan
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
index e0e0794..d38a2d2 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
@@ -8,10 +8,6 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// XFAIL: !has-64-bit-atomics
-// Older versions of clang have a bug with atomic builtins affecting double and long double.
-// Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
-
// floating-point-type operator-=(floating-point-type) volatile noexcept;
// floating-point-type operator-=(floating-point-type) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
index 7e2c101..c53b032 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
@@ -8,10 +8,6 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// XFAIL: !has-64-bit-atomics
-// Older versions of clang have a bug with atomic builtins affecting double and long double.
-// Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
-
// floating-point-type operator+=(floating-point-type) volatile noexcept;
// floating-point-type operator+=(floating-point-type) noexcept;
diff --git a/libcxx/test/libcxx/containers/associative/map/find.modules.compile.pass.mm b/libcxx/test/std/containers/associative/map/find.modules.compile.pass.mm
index 82b1c494..82b1c494 100644
--- a/libcxx/test/libcxx/containers/associative/map/find.modules.compile.pass.mm
+++ b/libcxx/test/std/containers/associative/map/find.modules.compile.pass.mm
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/empty.pass.cpp
index 4fa4fd6..a09bb8c 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/empty.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/empty.pass.cpp
@@ -26,7 +26,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<int>, KeyContainer, ValueContainer>;
@@ -41,11 +41,23 @@ void test() {
assert(m.empty());
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/max_size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/max_size.pass.cpp
index 0960c43..fc35fec 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/max_size.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/max_size.pass.cpp
@@ -26,7 +26,7 @@
#include "test_allocator.h"
#include "test_macros.h"
-int main(int, char**) {
+constexpr bool test() {
{
using A1 = limited_allocator<int, 10>;
using A2 = limited_allocator<int, 20>;
@@ -74,5 +74,15 @@ int main(int, char**) {
assert(c.max_size() <= max_dist);
assert(c.max_size() <= alloc_max_size(std::allocator<char>()));
}
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/size.pass.cpp
index 533f8da..3a99e20 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/size.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/size.pass.cpp
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200000000
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=800000000
// <flat_map>
@@ -25,7 +27,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using M = std::flat_multimap<int, char, std::less<int>, KeyContainer, ValueContainer>;
{
const M m = {{1, 'a'}, {1, 'b'}, {4, 'd'}, {5, 'e'}, {5, 'h'}};
@@ -47,7 +49,7 @@ void test() {
}
{
M m;
- std::size_t s = 1000;
+ std::size_t s = 500;
for (auto i = 0u; i < s; ++i) {
m.emplace(i, 'a');
}
@@ -60,11 +62,22 @@ void test() {
}
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<char>>();
- test<std::deque<int>, std::vector<char>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<char>>();
test<MinSequenceContainer<int>, MinSequenceContainer<char>>();
test<std::vector<int, min_allocator<int>>, std::vector<char, min_allocator<char>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/alloc.pass.cpp
index 3e155eb..596da81 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/alloc.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/alloc.pass.cpp
@@ -8,12 +8,13 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// <flat_map>
+// <flat_multimap>
// template<class Allocator>
// explicit flat_multimap(const Allocator& a);
#include <cassert>
+#include <deque>
#include <flat_map>
#include <functional>
#include <vector>
@@ -22,7 +23,23 @@
#include "test_allocator.h"
#include "../../../test_compare.h"
-int main(int, char**) {
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
+ using A = test_allocator<short>;
+ using M =
+ std::flat_multimap<int,
+ long,
+ std::less<int>,
+ KeyContainer<int, test_allocator<int>>,
+ ValueContainer<long, test_allocator<long>>>;
+ M m(A(0, 5));
+ assert(m.empty());
+ assert(m.begin() == m.end());
+ assert(m.keys().get_allocator().get_id() == 5);
+ assert(m.values().get_allocator().get_id() == 5);
+}
+
+constexpr bool test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<key_container_type, Alloc> is true
@@ -53,20 +70,23 @@ int main(int, char**) {
static_assert(std::is_constructible_v<M, test_allocator<int>>);
static_assert(!std::is_convertible_v<test_allocator<int>, M>);
}
+
+ test<std::vector, std::vector>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
{
- using A = test_allocator<short>;
- using M =
- std::flat_multimap<int,
- long,
- std::less<int>,
- std::vector<int, test_allocator<int>>,
- std::vector<long, test_allocator<long>>>;
- M m(A(0, 5));
- assert(m.empty());
- assert(m.begin() == m.end());
- assert(m.keys().get_allocator().get_id() == 5);
- assert(m.values().get_allocator().get_id() == 5);
+ test<std::deque, std::deque>();
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/assign_initializer_list.pass.cpp
index 32f75da..d3c4314 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/assign_initializer_list.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/assign_initializer_list.pass.cpp
@@ -24,18 +24,32 @@
#include "test_macros.h"
#include "min_allocator.h"
#include "test_allocator.h"
+#include "../helpers.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
{
M m = {{8, 8}, {10, 10}};
assert(m.size() == 2);
- m = {{3, 0}, {1, 0}, {2, 0}, {2, 1}, {3, 1}, {4, 0}, {3, 2}, {5, 0}, {6, 0}, {5, 1}};
- std::pair<int, int> expected[] = {{1, 0}, {2, 0}, {2, 1}, {3, 0}, {3, 1}, {3, 2}, {4, 0}, {5, 0}, {5, 1}, {6, 0}};
- assert(std::ranges::equal(m, expected));
+ m = {{3, 0}, {1, 0}, {2, 0}, {2, 1}, {3, 1}, {4, 0}, {3, 2}, {5, 0}, {6, 0}, {5, 1}};
+ assert(std::ranges::equal(m.keys(), std::vector{{1, 2, 2, 3, 3, 3, 4, 5, 5, 6}}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<Value>>{
+ {0},
+ {0, 1},
+ {0, 1},
+ {0, 1, 2},
+ {0, 1, 2},
+ {0, 1, 2},
+ {0},
+ {0, 1},
+ {0, 1},
+ {0},
+ });
}
{
M m = {{10, 1}, {8, 1}};
@@ -46,13 +60,28 @@ void test() {
}
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<int>>();
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque<int>, std::vector<double>>();
+ }
+
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/compare.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/compare.pass.cpp
index 1989b8a..8af02a2 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/compare.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/compare.pass.cpp
@@ -20,48 +20,52 @@
#include <type_traits>
#include <vector>
+#include "MinSequenceContainer.h"
+#include "min_allocator.h"
#include "test_macros.h"
#include "../../../test_compare.h"
#include "test_allocator.h"
-int main(int, char**) {
+// explicit flat_multimap(const key_compare& comp);
+template <class KeyContainer, class ValueContainer>
+constexpr void test_compare() {
+ using Key = typename KeyContainer::value_type;
+ using Value = typename ValueContainer::value_type;
{
- // The constructors in this subclause shall not participate in overload
- // resolution unless uses_allocator_v<key_container_type, Alloc> is true
- // and uses_allocator_v<mapped_container_type, Alloc> is true.
+ // The one-argument ctor is explicit.
+ using C = test_less<Key>;
+ static_assert(std::is_constructible_v<std::flat_multimap<Key, Value, C>, C>);
+ static_assert(!std::is_convertible_v<C, std::flat_multimap<Key, Value, C>>);
- using C = test_less<int>;
- using A1 = test_allocator<int>;
- using A2 = other_allocator<int>;
- using M1 = std::flat_multimap<int, int, C, std::vector<int, A1>, std::vector<int, A1>>;
- using M2 = std::flat_multimap<int, int, C, std::vector<int, A1>, std::vector<int, A2>>;
- using M3 = std::flat_multimap<int, int, C, std::vector<int, A2>, std::vector<int, A1>>;
- static_assert(std::is_constructible_v<M1, const C&, const A1&>);
- static_assert(!std::is_constructible_v<M1, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M2, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M3, const C&, const A2&>);
+ static_assert(std::is_constructible_v<std::flat_multimap<Key, Value>, std::less<Key>>);
+ static_assert(!std::is_convertible_v<std::less<Key>, std::flat_multimap<Key, Value>>);
}
{
- using C = test_less<int>;
- auto m = std::flat_multimap<int, char*, C>(C(3));
+ using C = test_less<Key>;
+ auto m = std::flat_multimap<Key, Value, C>(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<int>;
- static_assert(std::is_constructible_v<std::flat_multimap<int, char*, C>, C>);
- static_assert(!std::is_convertible_v<C, std::flat_multimap<int, char*, C>>);
+}
- static_assert(std::is_constructible_v<std::flat_multimap<int, char*>, std::less<int>>);
- static_assert(!std::is_convertible_v<std::less<int>, std::flat_multimap<int, char*>>);
+// template <class Alloc>
+// flat_multimap(const key_compare& comp, const Alloc& a);
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test_compare_alloc() {
+ {
+ // If an allocator is given, it must be usable by both containers.
+ using A = test_allocator<int>;
+ using M = std::flat_multimap<int, int, std::less<>, KeyContainer<int>, ValueContainer<int, A>>;
+ static_assert(std::is_constructible_v<M, std::less<>>);
+ static_assert(!std::is_constructible_v<M, std::less<>, std::allocator<int>>);
+ static_assert(!std::is_constructible_v<M, std::less<>, A>);
}
{
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = test_allocator<short>;
- auto m = std::flat_multimap<int, short, C, std::vector<int, A1>, std::vector<short, A2>>(C(4), A1(5));
+ auto m = std::flat_multimap<int, short, C, KeyContainer<int, A1>, ValueContainer<short, A2>>(C(4), A1(5));
assert(m.empty());
assert(m.begin() == m.end());
assert(m.key_comp() == C(4));
@@ -70,24 +74,60 @@ int main(int, char**) {
}
{
// explicit(false)
- using C = test_less<int>;
- using A1 = test_allocator<int>;
- using A2 = test_allocator<short>;
- std::flat_multimap<int, short, C, std::deque<int, A1>, std::deque<short, A2>> m = {C(4), A1(5)};
+ using C = test_less<int>;
+ using A1 = test_allocator<int>;
+ using A2 = test_allocator<short>;
+ std::flat_multimap<int, short, C, KeyContainer<int, A1>, ValueContainer<short, A2>> m = {C(4), A1(5)};
assert(m.empty());
assert(m.begin() == m.end());
assert(m.key_comp() == C(4));
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
}
+}
+
+constexpr bool test() {
{
- // If an allocator is given, it must be usable by both containers.
- using A = test_allocator<int>;
- using M = std::flat_multimap<int, int, std::less<>, std::vector<int>, std::vector<int, A>>;
- static_assert(std::is_constructible_v<M, std::less<>>);
- static_assert(!std::is_constructible_v<M, std::less<>, std::allocator<int>>);
- static_assert(!std::is_constructible_v<M, std::less<>, A>);
+ // The constructors in this subclause shall not participate in overload
+ // resolution unless uses_allocator_v<key_container_type, Alloc> is true
+ // and uses_allocator_v<mapped_container_type, Alloc> is true.
+
+ using C = test_less<int>;
+ using A1 = test_allocator<int>;
+ using A2 = other_allocator<int>;
+ using M1 = std::flat_multimap<int, int, C, std::vector<int, A1>, std::vector<int, A1>>;
+ using M2 = std::flat_multimap<int, int, C, std::vector<int, A1>, std::vector<int, A2>>;
+ using M3 = std::flat_multimap<int, int, C, std::vector<int, A2>, std::vector<int, A1>>;
+ static_assert(std::is_constructible_v<M1, const C&, const A1&>);
+ static_assert(!std::is_constructible_v<M1, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M2, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M3, const C&, const A2&>);
+ }
+
+ test_compare<std::vector<int>, std::vector<int>>();
+ test_compare<std::vector<int>, std::vector<double>>();
+ test_compare<MinSequenceContainer<int>, MinSequenceContainer<double>>();
+ test_compare<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
+ test_compare<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
+
+ test_compare_alloc<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test_compare<std::deque<int>, std::vector<double>>();
+ test_compare_alloc<std::deque, std::deque>();
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/containers.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/containers.pass.cpp
index 17ee3c3..2bb8035 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/containers.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/containers.pass.cpp
@@ -30,49 +30,40 @@
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
+#include "../helpers.h"
#include "../../../test_compare.h"
struct P {
int first;
int second;
template <class T, class U>
- bool operator==(const std::pair<T, U>& rhs) const {
+ constexpr bool operator==(const std::pair<T, U>& rhs) const {
return MoveOnly(first) == rhs.first && MoveOnly(second) == rhs.second;
}
};
-int main(int, char**) {
- {
- // The constructors in this subclause shall not participate in overload
- // resolution unless uses_allocator_v<key_container_type, Alloc> is true
- // and uses_allocator_v<mapped_container_type, Alloc> is true.
-
- using C = test_less<int>;
- using A1 = test_allocator<int>;
- using A2 = other_allocator<int>;
- using V1 = std::vector<int, A1>;
- using V2 = std::vector<int, A2>;
- using M1 = std::flat_multimap<int, int, C, V1, V1>;
- using M2 = std::flat_multimap<int, int, C, V1, V2>;
- using M3 = std::flat_multimap<int, int, C, V2, V1>;
- static_assert(std::is_constructible_v<M1, const V1&, const V1&, const A1&>);
- static_assert(!std::is_constructible_v<M1, const V1&, const V1&, const A2&>);
- static_assert(!std::is_constructible_v<M2, const V1&, const V2&, const A2&>);
- static_assert(!std::is_constructible_v<M3, const V2&, const V1&, const A2&>);
-
- static_assert(std::is_constructible_v<M1, const V1&, const V1&, const C&, const A1&>);
- static_assert(!std::is_constructible_v<M1, const V1&, const V1&, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M2, const V1&, const V2&, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M3, const V2&, const V1&, const C&, const A2&>);
- }
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
{
// flat_multimap(key_container_type , mapped_container_type)
- using M = std::flat_multimap<int, char>;
- std::vector<int> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3};
- std::vector<char> vs = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto m = M(ks, vs);
- std::pair<int, char> expected[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {2, 7}, {3, 6}, {3, 8}, {3, 9}};
- assert(std::ranges::equal(m, expected));
+ using M = std::flat_multimap<int, short, std::less<int>, KeyContainer<int>, ValueContainer<short>>;
+ KeyContainer<int> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3};
+ ValueContainer<short> vs = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ auto m = M(ks, vs);
+ assert((m.keys() == KeyContainer<int>{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<short>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
// explicit(false)
M m2 = {ks, vs};
@@ -81,18 +72,30 @@ int main(int, char**) {
m = M(std::move(ks), std::move(vs));
assert(ks.empty()); // it was moved-from
assert(vs.empty()); // it was moved-from
- assert(std::ranges::equal(m, expected));
+ assert((m.keys() == KeyContainer<int>{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<short>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
}
{
// flat_multimap(key_container_type , mapped_container_type)
// move-only
- P expected[] = {{3, 3}, {3, 2}, {2, 1}, {1, 4}};
- using Ks = std::deque<int, min_allocator<int>>;
- using Vs = std::vector<MoveOnly, min_allocator<MoveOnly>>;
+ P expected[] = {{3, 2}, {2, 1}, {1, 3}};
+ using Ks = KeyContainer<int, min_allocator<int>>;
+ using Vs = ValueContainer<MoveOnly, min_allocator<MoveOnly>>;
using M = std::flat_multimap<int, MoveOnly, std::greater<int>, Ks, Vs>;
- Ks ks = {1, 3, 3, 2};
+ Ks ks = {1, 3, 2};
Vs vs;
- vs.push_back(4);
vs.push_back(3);
vs.push_back(2);
vs.push_back(1);
@@ -105,26 +108,38 @@ int main(int, char**) {
// flat_multimap(key_container_type , mapped_container_type)
// container's allocators are used
using A = test_allocator<int>;
- using M = std::flat_multimap<int, int, std::less<int>, std::vector<int, A>, std::deque<int, A>>;
- auto ks = std::vector<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5));
- auto vs = std::deque<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(6));
+ using M = std::flat_multimap<int, int, std::less<int>, KeyContainer<int, A>, ValueContainer<int, A>>;
+ auto ks = KeyContainer<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5));
+ auto vs = ValueContainer<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(6));
auto m = M(std::move(ks), std::move(vs));
assert(ks.empty()); // it was moved-from
assert(vs.empty()); // it was moved-from
- std::pair<int, int> expected[] = {{1, 1}, {1, 1}, {1, 1}, {2, 2}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {3, 3}};
- assert(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), std::vector{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ assert(std::ranges::equal(m.values(), std::vector{1, 1, 1, 2, 2, 2, 3, 3, 3}));
assert(m.keys().get_allocator() == A(5));
assert(m.values().get_allocator() == A(6));
}
{
// flat_multimap(key_container_type , mapped_container_type, key_compare)
- using C = test_less<int>;
- using M = std::flat_multimap<int, char, C>;
- std::vector<int> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3};
- std::vector<char> vs = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto m = M(ks, vs, C(4));
- std::pair<int, char> expected[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {2, 7}, {3, 6}, {3, 8}, {3, 9}};
- assert(std::ranges::equal(m, expected));
+ using C = test_less<int>;
+ using M = std::flat_multimap<int, char, C, KeyContainer<int>, ValueContainer<char>>;
+ KeyContainer<int> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3};
+ ValueContainer<char> vs = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ auto m = M(ks, vs, C(4));
+ assert((m.keys() == KeyContainer<int>{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<char>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.key_comp() == C(4));
// explicit(false)
@@ -135,14 +150,14 @@ int main(int, char**) {
{
// flat_multimap(key_container_type , mapped_container_type, const Allocator&)
using A = test_allocator<int>;
- using M = std::flat_multimap<int, int, std::less<int>, std::vector<int, A>, std::deque<int, A>>;
- auto ks = std::vector<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5));
- auto vs = std::deque<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(6));
+ using M = std::flat_multimap<int, int, std::less<int>, KeyContainer<int, A>, ValueContainer<int, A>>;
+ auto ks = KeyContainer<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5));
+ auto vs = ValueContainer<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(6));
auto m = M(ks, vs, A(4)); // replaces the allocators
assert(!ks.empty()); // it was an lvalue above
assert(!vs.empty()); // it was an lvalue above
- std::pair<int, int> expected[] = {{1, 1}, {1, 1}, {1, 1}, {2, 2}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {3, 3}};
- assert(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), std::vector{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ assert(std::ranges::equal(m.values(), std::vector{1, 1, 1, 2, 2, 2, 3, 3, 3}));
assert(m.keys().get_allocator() == A(4));
assert(m.values().get_allocator() == A(4));
}
@@ -150,27 +165,40 @@ int main(int, char**) {
// flat_multimap(key_container_type , mapped_container_type, const Allocator&)
// explicit(false)
using A = test_allocator<int>;
- using M = std::flat_multimap<int, int, std::less<int>, std::vector<int, A>, std::deque<int, A>>;
- auto ks = std::vector<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5));
- auto vs = std::deque<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(6));
+ using M = std::flat_multimap<int, int, std::less<int>, KeyContainer<int, A>, ValueContainer<int, A>>;
+ auto ks = KeyContainer<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5));
+ auto vs = ValueContainer<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(6));
M m = {ks, vs, A(4)}; // implicit ctor
assert(!ks.empty()); // it was an lvalue above
assert(!vs.empty()); // it was an lvalue above
- std::pair<int, int> expected[] = {{1, 1}, {1, 1}, {1, 1}, {2, 2}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {3, 3}};
- assert(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), std::vector{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ assert(std::ranges::equal(m.values(), std::vector{1, 1, 1, 2, 2, 2, 3, 3, 3}));
assert(m.keys().get_allocator() == A(4));
assert(m.values().get_allocator() == A(4));
}
+
{
// flat_multimap(key_container_type , mapped_container_type, key_compare, const Allocator&)
- using C = test_less<int>;
- using A = test_allocator<int>;
- using M = std::flat_multimap<int, int, C, std::vector<int, A>, std::vector<int, A>>;
- std::vector<int, A> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3};
- std::vector<int, A> vs = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto m = M(ks, vs, C(4), A(5));
- std::pair<int, char> expected[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {2, 7}, {3, 6}, {3, 8}, {3, 9}};
- assert(std::ranges::equal(m, expected));
+ using C = test_less<int>;
+ using A = test_allocator<int>;
+ using M = std::flat_multimap<int, int, C, std::vector<int, A>, std::vector<int, A>>;
+ std::vector<int, A> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3};
+ std::vector<int, A> vs = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ auto m = M(ks, vs, C(4), A(5));
+ assert(std::ranges::equal(m.keys(), std::vector{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<int>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.key_comp() == C(4));
assert(m.keys().get_allocator() == A(5));
assert(m.values().get_allocator() == A(5));
@@ -182,6 +210,51 @@ int main(int, char**) {
assert(m2.keys().get_allocator() == A(5));
assert(m2.values().get_allocator() == A(5));
}
+}
+
+bool constexpr test() {
+ {
+ // The constructors in this subclause shall not participate in overload
+ // resolution unless uses_allocator_v<key_container_type, Alloc> is true
+ // and uses_allocator_v<mapped_container_type, Alloc> is true.
+
+ using C = test_less<int>;
+ using A1 = test_allocator<int>;
+ using A2 = other_allocator<int>;
+ using V1 = std::vector<int, A1>;
+ using V2 = std::vector<int, A2>;
+ using M1 = std::flat_multimap<int, int, C, V1, V1>;
+ using M2 = std::flat_multimap<int, int, C, V1, V2>;
+ using M3 = std::flat_multimap<int, int, C, V2, V1>;
+ static_assert(std::is_constructible_v<M1, const V1&, const V1&, const A1&>);
+ static_assert(!std::is_constructible_v<M1, const V1&, const V1&, const A2&>);
+ static_assert(!std::is_constructible_v<M2, const V1&, const V2&, const A2&>);
+ static_assert(!std::is_constructible_v<M3, const V2&, const V1&, const A2&>);
+
+ static_assert(std::is_constructible_v<M1, const V1&, const V1&, const C&, const A1&>);
+ static_assert(!std::is_constructible_v<M1, const V1&, const V1&, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M2, const V1&, const V2&, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M3, const V2&, const V1&, const C&, const A2&>);
+ }
+
+ test<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque, std::vector>();
+ test<std::deque, std::deque>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy.pass.cpp
index 0e6d12c..c2a782f 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy.pass.cpp
@@ -13,6 +13,7 @@
// flat_multimap(const flat_multimap& m);
#include <cassert>
+#include <deque>
#include <flat_map>
#include <vector>
@@ -20,11 +21,12 @@
#include "../../../test_compare.h"
#include "test_allocator.h"
-int main(int, char**) {
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
{
using C = test_less<int>;
- std::vector<int, test_allocator<int>> ks({1, 1, 3, 3, 5}, test_allocator<int>(6));
- std::vector<char, test_allocator<char>> vs({2, 2, 1, 1, 1}, test_allocator<char>(7));
+ KeyContainer<int, test_allocator<int>> ks({1, 1, 3, 5}, test_allocator<int>(6));
+ ValueContainer<char, test_allocator<char>> vs({2, 2, 2, 1}, test_allocator<char>(7));
using M = std::flat_multimap<int, char, C, decltype(ks), decltype(vs)>;
auto mo = M(ks, vs, C(5));
auto m = mo;
@@ -44,10 +46,10 @@ int main(int, char**) {
}
{
using C = test_less<int>;
- using Ks = std::vector<int, other_allocator<int>>;
- using Vs = std::vector<char, other_allocator<char>>;
- auto ks = Ks({1, 3, 5, 5, 5, 5}, other_allocator<int>(6));
- auto vs = Vs({2, 2, 5, 5, 5, 1}, other_allocator<char>(7));
+ using Ks = KeyContainer<int, other_allocator<int>>;
+ using Vs = ValueContainer<char, other_allocator<char>>;
+ auto ks = Ks({1, 1, 3, 5}, other_allocator<int>(6));
+ auto vs = Vs({2, 2, 2, 1}, other_allocator<char>(7));
using M = std::flat_multimap<int, char, C, Ks, Vs>;
auto mo = M(Ks(ks, other_allocator<int>(6)), Vs(vs, other_allocator<int>(7)), C(5));
auto m = mo;
@@ -65,6 +67,26 @@ int main(int, char**) {
assert(mo.keys().get_allocator() == other_allocator<int>(6));
assert(mo.values().get_allocator() == other_allocator<char>(7));
}
+}
+
+constexpr bool test() {
+ test<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque, std::deque>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_alloc.pass.cpp
index 3047c00..a26c349 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_alloc.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_alloc.pass.cpp
@@ -22,7 +22,30 @@
#include "../../../test_compare.h"
#include "test_allocator.h"
-int main(int, char**) {
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
+ using C = test_less<int>;
+ KeyContainer<int, test_allocator<int>> ks({1, 1, 3, 5}, test_allocator<int>(6));
+ ValueContainer<char, test_allocator<char>> vs({2, 2, 2, 1}, test_allocator<char>(7));
+ using M = std::flat_multimap<int, char, C, decltype(ks), decltype(vs)>;
+ auto mo = M(ks, vs, C(5));
+ auto m = M(mo, test_allocator<int>(3));
+
+ assert(m.key_comp() == C(5));
+ assert(m.keys() == ks);
+ assert(m.values() == vs);
+ assert(m.keys().get_allocator() == test_allocator<int>(3));
+ assert(m.values().get_allocator() == test_allocator<char>(3));
+
+ // mo is unchanged
+ assert(mo.key_comp() == C(5));
+ assert(mo.keys() == ks);
+ assert(mo.values() == vs);
+ assert(mo.keys().get_allocator() == test_allocator<int>(6));
+ assert(mo.values().get_allocator() == test_allocator<char>(7));
+}
+
+constexpr bool test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<key_container_type, Alloc> is true
@@ -41,27 +64,24 @@ int main(int, char**) {
static_assert(!std::is_constructible_v<M2, const M2&, const A2&>);
static_assert(!std::is_constructible_v<M3, const M3&, const A2&>);
}
- {
- using C = test_less<int>;
- std::vector<int, test_allocator<int>> ks({1, 3, 3, 5, 5}, test_allocator<int>(6));
- std::vector<char, test_allocator<char>> vs({2, 2, 1, 1, 1}, test_allocator<char>(7));
- using M = std::flat_multimap<int, char, C, decltype(ks), decltype(vs)>;
- auto mo = M(ks, vs, C(5));
- auto m = M(mo, test_allocator<int>(3));
- assert(m.key_comp() == C(5));
- assert(m.keys() == ks);
- assert(m.values() == vs);
- assert(m.keys().get_allocator() == test_allocator<int>(3));
- assert(m.values().get_allocator() == test_allocator<char>(3));
+ test<std::vector, std::vector>();
- // mo is unchanged
- assert(mo.key_comp() == C(5));
- assert(mo.keys() == ks);
- assert(mo.values() == vs);
- assert(mo.keys().get_allocator() == test_allocator<int>(6));
- assert(mo.values().get_allocator() == test_allocator<char>(7));
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque, std::deque>();
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_assign.pass.cpp
index 3dd7ebd..fd57a10 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_assign.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_assign.pass.cpp
@@ -15,21 +15,23 @@
#include <deque>
#include <flat_map>
#include <functional>
+#include <type_traits>
#include <vector>
#include "test_macros.h"
#include "../../../test_compare.h"
#include "test_allocator.h"
-int main(int, char**) {
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
{
// test_allocator is not propagated
using C = test_less<int>;
- std::vector<int, test_allocator<int>> ks({1, 1, 3, 3, 5}, test_allocator<int>(6));
- std::vector<char, test_allocator<char>> vs({1, 2, 3, 4, 5}, test_allocator<char>(7));
+ KeyContainer<int, test_allocator<int>> ks({1, 1, 3, 5}, test_allocator<int>(6));
+ ValueContainer<char, test_allocator<char>> vs({2, 2, 2, 1}, test_allocator<char>(7));
using M = std::flat_multimap<int, char, C, decltype(ks), decltype(vs)>;
auto mo = M(ks, vs, C(5));
- auto m = M({{3, 3}, {4, 4}, {5, 5}}, C(3), test_allocator<int>(2));
+ auto m = M({{3, 3}, {4, 4}, {5, 5}, {5, 5}}, C(3), test_allocator<int>(2));
m = mo;
assert(m.key_comp() == C(5));
@@ -48,13 +50,13 @@ int main(int, char**) {
{
// other_allocator is propagated
using C = test_less<int>;
- using Ks = std::vector<int, other_allocator<int>>;
- using Vs = std::vector<char, other_allocator<char>>;
- auto ks = Ks({1, 1, 3, 3, 5}, other_allocator<int>(6));
- auto vs = Vs({2, 1, 3, 2, 1}, other_allocator<char>(7));
+ using Ks = KeyContainer<int, other_allocator<int>>;
+ using Vs = ValueContainer<char, other_allocator<char>>;
+ auto ks = Ks({1, 1, 3, 5}, other_allocator<int>(6));
+ auto vs = Vs({2, 2, 2, 1}, other_allocator<char>(7));
using M = std::flat_multimap<int, char, C, Ks, Vs>;
auto mo = M(Ks(ks, other_allocator<int>(6)), Vs(vs, other_allocator<int>(7)), C(5));
- auto m = M({{3, 3}, {4, 4}, {5, 5}}, C(3), other_allocator<int>(2));
+ auto m = M({{3, 3}, {4, 4}, {5, 5}, {5, 5}}, C(3), other_allocator<int>(2));
m = mo;
assert(m.key_comp() == C(5));
@@ -70,12 +72,44 @@ int main(int, char**) {
assert(mo.keys().get_allocator() == other_allocator<int>(6));
assert(mo.values().get_allocator() == other_allocator<char>(7));
}
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ // comparator is copied and invariant is preserved
+ using M = std::flat_multimap<int, int, std::function<bool(int, int)>>;
+ M mo = M({{1, 2}, {3, 4}}, std::less<int>());
+ M m = M({{1, 2}, {3, 4}}, std::greater<int>());
+ 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_multimap<int, int>;
- M m = {{1, 1}, {3, 4}};
+ M m = {{1, 2}, {3, 4}};
m = static_cast<const M&>(m);
- assert((m == M{{1, 1}, {3, 4}}));
+ assert((m == M{{1, 2}, {3, 4}}));
+ }
+}
+
+constexpr bool test() {
+ test<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque, std::deque>();
}
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default.pass.cpp
index c910f74..4e5490b 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default.pass.cpp
@@ -24,23 +24,24 @@
#include "test_allocator.h"
struct DefaultCtableComp {
- explicit DefaultCtableComp() { default_constructed_ = true; }
- bool operator()(int, int) const { return false; }
+ constexpr explicit DefaultCtableComp() { default_constructed_ = true; }
+ constexpr bool operator()(int, int) const { return false; }
bool default_constructed_ = false;
};
-int main(int, char**) {
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
{
- std::flat_multimap<int, char*> m;
+ std::flat_multimap<int, char*, std::less<int>, KeyContainer<int>, ValueContainer<char*>> m;
assert(m.empty());
}
{
// explicit(false)
- std::flat_multimap<int, char*> m = {};
+ std::flat_multimap<int, char*, std::less<int>, KeyContainer<int>, ValueContainer<char*>> m = {};
assert(m.empty());
}
{
- std::flat_multimap<int, char*, DefaultCtableComp, std::deque<int, min_allocator<int>>> m;
+ std::flat_multimap<int, char*, DefaultCtableComp, KeyContainer<int, min_allocator<int>>> m;
assert(m.empty());
assert(m.begin() == m.end());
assert(m.key_comp().default_constructed_);
@@ -49,13 +50,13 @@ int main(int, char**) {
using A1 = explicit_allocator<int>;
using A2 = explicit_allocator<char*>;
{
- std::flat_multimap<int, char*, DefaultCtableComp, std::vector<int, A1>, std::vector<char*, A2>> m;
+ std::flat_multimap<int, char*, DefaultCtableComp, KeyContainer<int, A1>, ValueContainer<char*, A2>> m;
assert(m.empty());
assert(m.key_comp().default_constructed_);
}
{
A1 a1;
- std::flat_multimap<int, int, DefaultCtableComp, std::vector<int, A1>, std::vector<int, A1>> m(a1);
+ std::flat_multimap<int, int, DefaultCtableComp, KeyContainer<int, A1>, ValueContainer<int, A1>> m(a1);
assert(m.empty());
assert(m.key_comp().default_constructed_);
}
@@ -63,10 +64,31 @@ int main(int, char**) {
{
// If an allocator is given, it must be usable by both containers.
using A = test_allocator<int>;
- using M = std::flat_multimap<int, int, std::less<>, std::vector<int>, std::vector<int, A>>;
+ using M = std::flat_multimap<int, int, std::less<>, KeyContainer<int>, ValueContainer<int, A>>;
static_assert(std::is_constructible_v<M>);
static_assert(!std::is_constructible_v<M, std::allocator<int>>);
static_assert(!std::is_constructible_v<M, A>);
}
+}
+
+constexpr bool test() {
+ test<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque, std::deque>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default_noexcept.pass.cpp
index fa490f1..49df556 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default_noexcept.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default_noexcept.pass.cpp
@@ -28,11 +28,11 @@
#include "test_allocator.h"
struct ThrowingCtorComp {
- ThrowingCtorComp() noexcept(false) {}
- bool operator()(const auto&, const auto&) const { return false; }
+ constexpr ThrowingCtorComp() noexcept(false) {}
+ constexpr bool operator()(const auto&, const auto&) const { return false; }
};
-int main(int, char**) {
+constexpr bool test() {
#if defined(_LIBCPP_VERSION)
{
using C = std::flat_multimap<MoveOnly, MoveOnly>;
@@ -57,5 +57,14 @@ int main(int, char**) {
static_assert(!std::is_nothrow_default_constructible_v<C>);
C c;
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/dtor_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/dtor_noexcept.pass.cpp
index fd31e44..104d567 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/dtor_noexcept.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/dtor_noexcept.pass.cpp
@@ -23,35 +23,60 @@
#include "test_allocator.h"
struct ThrowingDtorComp {
- bool operator()(const auto&, const auto&) const;
- ~ThrowingDtorComp() noexcept(false) {}
+ constexpr bool operator()(const auto&, const auto&) const;
+ constexpr ~ThrowingDtorComp() noexcept(false) {}
};
-int main(int, char**) {
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
{
- using C = std::flat_multimap<MoveOnly, MoveOnly>;
+ using C =
+ std::flat_multimap<MoveOnly, MoveOnly, std::less<MoveOnly>, KeyContainer<MoveOnly>, ValueContainer<MoveOnly>>;
static_assert(std::is_nothrow_destructible_v<C>);
C c;
}
{
- using V = std::vector<MoveOnly, test_allocator<MoveOnly>>;
- using C = std::flat_multimap<MoveOnly, MoveOnly, std::less<MoveOnly>, V, V>;
+ using V = KeyContainer<MoveOnly, test_allocator<MoveOnly>>;
+ using V2 = ValueContainer<MoveOnly, test_allocator<MoveOnly>>;
+ using C = std::flat_multimap<MoveOnly, MoveOnly, std::less<MoveOnly>, V, V2>;
static_assert(std::is_nothrow_destructible_v<C>);
C c;
}
{
- using V = std::deque<MoveOnly, other_allocator<MoveOnly>>;
- using C = std::flat_multimap<MoveOnly, MoveOnly, std::greater<MoveOnly>, V, V>;
+ using V = KeyContainer<MoveOnly, test_allocator<MoveOnly>>;
+ using V2 = ValueContainer<MoveOnly, test_allocator<MoveOnly>>;
+ using C = std::flat_multimap<MoveOnly, MoveOnly, std::greater<MoveOnly>, V, V2>;
static_assert(std::is_nothrow_destructible_v<C>);
C c;
}
#if defined(_LIBCPP_VERSION)
{
- using C = std::flat_multimap<MoveOnly, MoveOnly, ThrowingDtorComp>;
+ using C =
+ std::flat_multimap<MoveOnly, MoveOnly, ThrowingDtorComp, KeyContainer<MoveOnly>, ValueContainer<MoveOnly>>;
static_assert(!std::is_nothrow_destructible_v<C>);
C c;
}
#endif // _LIBCPP_VERSION
+}
+
+constexpr bool test() {
+ test<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque, std::deque>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/initializer_list.pass.cpp
index 8e89192..e40708a 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/initializer_list.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/initializer_list.pass.cpp
@@ -31,12 +31,84 @@
#include "../../../test_compare.h"
struct DefaultCtableComp {
- explicit DefaultCtableComp() { default_constructed_ = true; }
- bool operator()(int, int) const { return false; }
+ constexpr explicit DefaultCtableComp() { default_constructed_ = true; }
+ constexpr bool operator()(int, int) const { return false; }
bool default_constructed_ = false;
};
-int main(int, char**) {
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
+ std::pair<int, short> expected[] = {{1, 1}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {5, 2}};
+ {
+ // flat_multimap(initializer_list<value_type>);
+ using M = std::flat_multimap<int, short>;
+ std::initializer_list<std::pair<int, short>> il = {{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}};
+ M m(il);
+ assert(std::ranges::equal(m, expected));
+ }
+ {
+ // flat_multimap(initializer_list<value_type>);
+ // explicit(false)
+ using M = std::flat_multimap<int, short>;
+ M m = {{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}};
+ assert(std::ranges::equal(m, expected));
+ }
+ {
+ // flat_multimap(initializer_list<value_type>);
+ using M = std::flat_multimap<int, short, std::greater<int>, KeyContainer<int, min_allocator<int>>>;
+ M m = {{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}};
+ assert(std::equal(m.rbegin(), m.rend(), expected, expected + 6));
+ }
+ {
+ // flat_multimap(initializer_list<value_type>);
+ // different comparator
+ using A = explicit_allocator<int>;
+ using M = std::flat_multimap<int, int, DefaultCtableComp, KeyContainer<int, A>, ValueContainer<int, A>>;
+ M m = {{1, 1}, {2, 2}, {3, 3}};
+ assert(m.size() == 3);
+ assert(m.begin()->first == m.begin()->second);
+ assert(m.key_comp().default_constructed_);
+ }
+ {
+ // flat_multimap(initializer_list<value_type>, const Allocator&);
+ using A = explicit_allocator<int>;
+ using M = std::flat_multimap<int, int, std::greater<int>, KeyContainer<int, A>, ValueContainer<int, A>>;
+ A a;
+ M m({{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}}, a);
+ assert(std::equal(m.rbegin(), m.rend(), expected, expected + 6));
+ }
+ {
+ // flat_multimap(initializer_list<value_type>, const key_compare&);
+ using C = test_less<int>;
+ using M = std::flat_multimap<int, short, C>;
+ auto m = M({{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}}, C(10));
+ assert(std::equal(m.begin(), m.end(), expected, expected + 6));
+ assert(m.key_comp() == C(10));
+
+ // explicit(false)
+ M m2 = {{{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}}, C(10)};
+ assert(m2 == m);
+ assert(m2.key_comp() == C(10));
+ }
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ // flat_multimap(initializer_list<value_type>, const key_compare&);
+ // Sorting uses the comparator that was passed in
+ using M = std::flat_multimap<int, short, std::function<bool(int, int)>, KeyContainer<int, min_allocator<int>>>;
+ auto m = M({{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}}, std::greater<int>());
+ assert(std::equal(m.rbegin(), m.rend(), expected, expected + 6));
+ assert(m.key_comp()(2, 1) == true);
+ }
+ {
+ // flat_multimap(initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
+ using A = explicit_allocator<int>;
+ using M = std::flat_multimap<int, int, std::greater<int>, KeyContainer<int, A>, ValueContainer<int, A>>;
+ A a;
+ M m({{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}}, {}, a);
+ assert(std::equal(m.rbegin(), m.rend(), expected, expected + 6));
+ }
+}
+
+constexpr bool test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<key_container_type, Alloc> is true
@@ -83,77 +155,23 @@ int main(int, char**) {
!std::is_constructible_v<M, std::initializer_list<std::pair<const int, const short>>, std::allocator<int>>);
}
- std::pair<int, short> expected[] = {{1, 1}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {5, 2}};
- {
- // flat_multimap(initializer_list<value_type>);
- using M = std::flat_multimap<int, short>;
- std::initializer_list<std::pair<int, short>> il = {{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}};
- M m(il);
- assert(std::ranges::equal(m, expected));
- }
- {
- // flat_multimap(initializer_list<value_type>);
- // explicit(false)
- using M = std::flat_multimap<int, short>;
- M m = {{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}};
- assert(std::ranges::equal(m, expected));
- }
- {
- // flat_multimap(initializer_list<value_type>);
- using M = std::flat_multimap<int, short, std::greater<int>, std::deque<int, min_allocator<int>>>;
- M m = {{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}};
- assert(std::equal(m.rbegin(), m.rend(), expected, expected + 6));
- }
- {
- using A = explicit_allocator<int>;
- {
- // flat_multimap(initializer_list<value_type>);
- // different comparator
- using M = std::flat_multimap<int, int, DefaultCtableComp, std::vector<int, A>, std::deque<int, A>>;
- M m = {{1, 1}, {2, 2}, {3, 3}};
- assert(m.size() == 3);
-
- std::pair<int, int> expected1[] = {{1, 1}, {2, 2}, {3, 3}};
- assert(std::ranges::equal(m, expected1));
- assert(m.key_comp().default_constructed_);
- }
- {
- // flat_multimap(initializer_list<value_type>, const Allocator&);
- using M = std::flat_multimap<int, int, std::greater<int>, std::deque<int, A>, std::vector<int, A>>;
- A a;
- M m({{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}}, a);
- assert(std::equal(m.rbegin(), m.rend(), expected, expected + 6));
- }
- }
- {
- // flat_multimap(initializer_list<value_type>, const key_compare&);
- using C = test_less<int>;
- using M = std::flat_multimap<int, short, C>;
- auto m = M({{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}}, C(10));
- assert(std::ranges::equal(m, expected));
- assert(m.key_comp() == C(10));
+ test<std::vector, std::vector>();
- // explicit(false)
- M m2 = {{{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}}, C(10)};
- assert(m2 == m);
- assert(m2.key_comp() == C(10));
- }
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
{
- // flat_multimap(initializer_list<value_type>, const key_compare&);
- // Sorting uses the comparator that was passed in
- using M = std::flat_multimap<int, short, std::function<bool(int, int)>, std::deque<int, min_allocator<int>>>;
- auto m = M({{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}}, std::greater<int>());
- assert(std::equal(m.rbegin(), m.rend(), expected, expected + 6));
- assert(m.key_comp()(2, 1) == true);
- }
- {
- // flat_multimap(initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
- using A = explicit_allocator<int>;
- using M = std::flat_multimap<int, int, std::greater<int>, std::deque<int, A>, std::vector<int, A>>;
- A a;
- M m({{5, 2}, {2, 2}, {2, 2}, {3, 3}, {1, 1}, {3, 3}}, {}, a);
- assert(std::equal(m.rbegin(), m.rend(), expected, expected + 6));
+ test<std::deque, std::deque>();
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/iter_iter.pass.cpp
index c9c5e6c..c7f2d16 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/iter_iter.pass.cpp
@@ -22,51 +22,41 @@
#include <flat_map>
#include <functional>
#include <vector>
+#include <ranges>
+#include "MinSequenceContainer.h"
#include "min_allocator.h"
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
+#include "../helpers.h"
#include "../../../test_compare.h"
-int main(int, char**) {
- {
- // The constructors in this subclause shall not participate in overload
- // resolution unless uses_allocator_v<key_container_type, Alloc> is true
- // and uses_allocator_v<mapped_container_type, Alloc> is true.
-
- using C = test_less<int>;
- using A1 = test_allocator<int>;
- using A2 = other_allocator<int>;
- using V1 = std::vector<int, A1>;
- using V2 = std::vector<int, A2>;
- using M1 = std::flat_multimap<int, int, C, V1, V1>;
- using M2 = std::flat_multimap<int, int, C, V1, V2>;
- using M3 = std::flat_multimap<int, int, C, V2, V1>;
- using Iter1 = typename M1::iterator;
- using Iter2 = typename M2::iterator;
- using Iter3 = typename M3::iterator;
- static_assert(std::is_constructible_v<M1, Iter1, Iter1, const A1&>);
- static_assert(!std::is_constructible_v<M1, Iter1, Iter1, const A2&>);
- static_assert(!std::is_constructible_v<M2, Iter2, Iter2, const A2&>);
- static_assert(!std::is_constructible_v<M3, Iter3, Iter3, const A2&>);
-
- static_assert(std::is_constructible_v<M1, Iter1, Iter1, const C&, const A1&>);
- static_assert(!std::is_constructible_v<M1, Iter1, Iter1, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M2, Iter2, Iter2, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M3, Iter3, Iter3, const C&, const A2&>);
- }
-
- using P = std::pair<int, short>;
- P ar[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {2, 7}, {3, 8}, {3, 9}};
- P expected[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {2, 7}, {3, 6}, {3, 8}, {3, 9}};
+template <class KeyContainer, class ValueContainer>
+constexpr void test() {
+ using Key = typename KeyContainer::value_type;
+ using Value = typename ValueContainer::value_type;
+ using P = std::pair<Key, Value>;
+ P ar[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {2, 7}, {3, 8}, {3, 9}};
{
// flat_multimap(InputIterator , InputIterator)
// cpp17_input_iterator
- using M = std::flat_multimap<int, short>;
+ using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
auto m = M(cpp17_input_iterator<const P*>(ar), cpp17_input_iterator<const P*>(ar + 9));
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<Value>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
// explicit(false)
M m2 = {cpp17_input_iterator<const P*>(ar), cpp17_input_iterator<const P*>(ar + 9)};
@@ -75,25 +65,49 @@ int main(int, char**) {
{
// flat_multimap(InputIterator , InputIterator)
// greater
- using M = std::flat_multimap<int, short, std::greater<int>, std::deque<int, min_allocator<int>>, std::deque<short>>;
+ using M = std::flat_multimap<Key, Value, std::greater<Key>, KeyContainer, ValueContainer>;
auto m = M(cpp17_input_iterator<const P*>(ar), cpp17_input_iterator<const P*>(ar + 9));
- assert((m.keys() == std::deque<int, min_allocator<int>>{3, 3, 3, 2, 2, 2, 1, 1, 1}));
- LIBCPP_ASSERT((m.values() == std::deque<short>{6, 8, 9, 4, 5, 7, 1, 2, 3}));
+ assert(std::ranges::equal(m.keys(), KeyContainer{3, 3, 3, 2, 2, 2, 1, 1, 1}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<Value>>{
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ });
}
{
// flat_multimap(InputIterator , InputIterator)
// Test when the operands are of array type (also contiguous iterator type)
- using M = std::flat_multimap<int, short, std::greater<int>, std::vector<int, min_allocator<int>>>;
+ using M = std::flat_multimap<Key, Value, std::greater<Key>, KeyContainer, ValueContainer>;
auto m = M(ar, ar);
assert(m.empty());
}
{
// flat_multimap(InputIterator , InputIterator, const key_compare&)
- using C = test_less<int>;
- using M = std::flat_multimap<int, short, C, std::vector<int>, std::deque<short>>;
+ using C = test_less<Key>;
+ using M = std::flat_multimap<Key, Value, C, KeyContainer, ValueContainer>;
auto m = M(ar, ar + 9, C(3));
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<Value>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.key_comp() == C(3));
// explicit(false)
@@ -101,14 +115,33 @@ int main(int, char**) {
assert(m2 == m);
assert(m2.key_comp() == C(3));
}
+}
+
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test_alloc() {
+ using P = std::pair<int, short>;
+ P ar[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {2, 7}, {3, 8}, {3, 9}};
+
{
// flat_multimap(InputIterator , InputIterator, const Allocator&)
using A1 = test_allocator<int>;
using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, std::less<int>, std::vector<int, A1>, std::deque<short, A2>>;
+ using M = std::flat_multimap<int, short, std::less<int>, KeyContainer<int, A1>, ValueContainer<short, A2>>;
auto m = M(ar, ar + 9, A1(5));
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer<int, A1>{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<short>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
}
@@ -117,10 +150,22 @@ int main(int, char**) {
// explicit(false)
using A1 = test_allocator<int>;
using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, std::less<int>, std::vector<int, A1>, std::deque<short, A2>>;
+ using M = std::flat_multimap<int, short, std::less<int>, KeyContainer<int, A1>, ValueContainer<short, A2>>;
M m = {ar, ar + 9, A1(5)}; // implicit ctor
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer<int, A1>{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<short>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
}
@@ -129,10 +174,22 @@ int main(int, char**) {
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, C, std::vector<int, A1>, std::deque<short, A2>>;
+ using M = std::flat_multimap<int, short, C, KeyContainer<int, A1>, ValueContainer<short, A2>>;
auto m = M(ar, ar + 9, C(3), A1(5));
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer<int, A1>{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<short>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.key_comp() == C(3));
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
@@ -142,13 +199,79 @@ int main(int, char**) {
// explicit(false)
using A1 = test_allocator<int>;
using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, std::less<int>, std::deque<int, A1>, std::vector<short, A2>>;
+ using M = std::flat_multimap<int, short, std::less<int>, KeyContainer<int, A1>, ValueContainer<short, A2>>;
M m = {ar, ar + 9, {}, A2(5)}; // implicit ctor
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer<int, A1>{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<short>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
}
+}
+
+constexpr bool test() {
+ {
+ // The constructors in this subclause shall not participate in overload
+ // resolution unless uses_allocator_v<key_container_type, Alloc> is true
+ // and uses_allocator_v<mapped_container_type, Alloc> is true.
+
+ using C = test_less<int>;
+ using A1 = test_allocator<int>;
+ using A2 = other_allocator<int>;
+ using V1 = std::vector<int, A1>;
+ using V2 = std::vector<int, A2>;
+ using M1 = std::flat_multimap<int, int, C, V1, V1>;
+ using M2 = std::flat_multimap<int, int, C, V1, V2>;
+ using M3 = std::flat_multimap<int, int, C, V2, V1>;
+ using Iter1 = typename M1::iterator;
+ using Iter2 = typename M2::iterator;
+ using Iter3 = typename M3::iterator;
+ static_assert(std::is_constructible_v<M1, Iter1, Iter1, const A1&>);
+ static_assert(!std::is_constructible_v<M1, Iter1, Iter1, const A2&>);
+ static_assert(!std::is_constructible_v<M2, Iter2, Iter2, const A2&>);
+ static_assert(!std::is_constructible_v<M3, Iter3, Iter3, const A2&>);
+
+ static_assert(std::is_constructible_v<M1, Iter1, Iter1, const C&, const A1&>);
+ static_assert(!std::is_constructible_v<M1, Iter1, Iter1, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M2, Iter2, Iter2, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M3, Iter3, Iter3, const C&, const A2&>);
+ }
+
+ test<std::vector<int>, std::vector<int>>();
+ test<std::vector<int>, std::vector<double>>();
+ test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
+ test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
+ test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
+
+ test_alloc<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque<int>, std::vector<double>>();
+ test_alloc<std::deque, std::deque>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move.pass.cpp
index 893c9247..bb9ea9e 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move.pass.cpp
@@ -16,6 +16,7 @@
#include <deque>
#include <flat_map>
#include <functional>
+#include <type_traits>
#include <utility>
#include <vector>
@@ -25,11 +26,12 @@
#include "test_allocator.h"
#include "min_allocator.h"
-int main(int, char**) {
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
{
using C = test_less<int>;
using A = test_allocator<int>;
- using M = std::flat_multimap<int, int, C, std::vector<int, A>, std::deque<int, A>>;
+ using M = std::flat_multimap<int, int, C, KeyContainer<int, A>, ValueContainer<int, A>>;
M mo = M({{1, 1}, {1, 2}, {3, 1}}, C(5), A(7));
M m = std::move(mo);
assert((m == M{{1, 1}, {1, 2}, {3, 1}}));
@@ -45,7 +47,7 @@ int main(int, char**) {
{
using C = test_less<int>;
using A = min_allocator<int>;
- using M = std::flat_multimap<int, int, C, std::vector<int, A>, std::deque<int, A>>;
+ using M = std::flat_multimap<int, int, C, KeyContainer<int, A>, ValueContainer<int, A>>;
M mo = M({{1, 1}, {1, 2}, {3, 1}}, C(5), A());
M m = std::move(mo);
assert((m == M{{1, 1}, {1, 2}, {3, 1}}));
@@ -58,9 +60,9 @@ int main(int, char**) {
assert(m.keys().get_allocator() == A());
assert(m.values().get_allocator() == A());
}
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
// A moved-from flat_multimap maintains its class invariant in the presence of moved-from comparators.
- using M = std::flat_multimap<int, int, std::function<bool(int, int)>>;
+ using M = std::flat_multimap<int, int, std::function<bool(int, int)>, KeyContainer<int>, ValueContainer<int>>;
M mo = M({{1, 1}, {1, 2}, {3, 1}}, std::less<int>());
M m = std::move(mo);
assert(m.size() == 3);
@@ -75,7 +77,7 @@ int main(int, char**) {
}
{
// moved-from object maintains invariant if one of underlying container does not clear after move
- using M = std::flat_multimap<int, int, std::less<>, std::vector<int>, CopyOnlyVector<int>>;
+ using M = std::flat_multimap<int, int, std::less<>, KeyContainer<int>, CopyOnlyVector<int>>;
M m1 = M({1, 1, 3}, {1, 2, 3});
M m2 = std::move(m1);
assert(m2.size() == 3);
@@ -84,6 +86,26 @@ int main(int, char**) {
LIBCPP_ASSERT(m1.keys().size() == 0);
LIBCPP_ASSERT(m1.values().size() == 0);
}
+}
+
+constexpr bool test() {
+ test<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque, std::deque>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_alloc.pass.cpp
index a0259e8..140cada 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_alloc.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_alloc.pass.cpp
@@ -24,30 +24,13 @@
#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<key_container_type, Alloc> is true
- // and uses_allocator_v<mapped_container_type, Alloc> is true.
-
- using C = test_less<int>;
- using A1 = test_allocator<int>;
- using A2 = other_allocator<int>;
- using V1 = std::vector<int, A1>;
- using V2 = std::vector<int, A2>;
- using M1 = std::flat_multimap<int, int, C, V1, V1>;
- using M2 = std::flat_multimap<int, int, C, V1, V2>;
- using M3 = std::flat_multimap<int, int, C, V2, V1>;
- static_assert(std::is_constructible_v<M1, M1&&, const A1&>);
- static_assert(!std::is_constructible_v<M1, M1&&, const A2&>);
- static_assert(!std::is_constructible_v<M2, M2&&, const A2&>);
- static_assert(!std::is_constructible_v<M3, M3&&, const A2&>);
- }
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
{
std::pair<int, int> expected[] = {{1, 1}, {1, 2}, {2, 3}, {2, 2}, {3, 1}};
using C = test_less<int>;
using A = test_allocator<int>;
- using M = std::flat_multimap<int, int, C, std::vector<int, A>, std::deque<int, A>>;
+ using M = std::flat_multimap<int, int, C, KeyContainer<int, A>, ValueContainer<int, A>>;
auto mo = M(expected, expected + 5, C(5), A(7));
auto m = M(std::move(mo), A(3));
@@ -57,7 +40,15 @@ int main(int, char**) {
assert(keys.get_allocator() == A(3));
assert(values.get_allocator() == A(3));
assert(std::ranges::equal(keys, expected | std::views::elements<0>));
- assert(std::ranges::equal(values, expected | std::views::elements<1>));
+ check_possible_values(
+ values,
+ std::vector<std::vector<int>>{
+ {1, 2},
+ {1, 2},
+ {2, 3},
+ {2, 3},
+ {1},
+ });
// The original flat_multimap is moved-from.
assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp()));
@@ -68,8 +59,8 @@ int main(int, char**) {
}
{
// moved-from object maintains invariant if one of underlying container does not clear after move
- using M = std::flat_multimap<int, int, std::less<>, std::vector<int>, CopyOnlyVector<int>>;
- M m1 = M({1, 1, 3}, {1, 2, 3});
+ using M = std::flat_multimap<int, int, std::less<>, KeyContainer<int>, CopyOnlyVector<int>>;
+ M m1 = M({1, 2, 3}, {1, 2, 3});
M m2(std::move(m1), std::allocator<int>{});
assert(m2.size() == 3);
check_invariant(m1);
@@ -77,6 +68,45 @@ int main(int, char**) {
LIBCPP_ASSERT(m1.keys().size() == 0);
LIBCPP_ASSERT(m1.values().size() == 0);
}
+}
+
+constexpr bool test() {
+ {
+ // The constructors in this subclause shall not participate in overload
+ // resolution unless uses_allocator_v<key_container_type, Alloc> is true
+ // and uses_allocator_v<mapped_container_type, Alloc> is true.
+
+ using C = test_less<int>;
+ using A1 = test_allocator<int>;
+ using A2 = other_allocator<int>;
+ using V1 = std::vector<int, A1>;
+ using V2 = std::vector<int, A2>;
+ using M1 = std::flat_multimap<int, int, C, V1, V1>;
+ using M2 = std::flat_multimap<int, int, C, V1, V2>;
+ using M3 = std::flat_multimap<int, int, C, V2, V1>;
+ static_assert(std::is_constructible_v<M1, M1&&, const A1&>);
+ static_assert(!std::is_constructible_v<M1, M1&&, const A2&>);
+ static_assert(!std::is_constructible_v<M2, M2&&, const A2&>);
+ static_assert(!std::is_constructible_v<M3, M3&&, const A2&>);
+ }
+
+ test<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque, std::deque>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign.pass.cpp
index 38200d0..292bb5c 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign.pass.cpp
@@ -26,12 +26,13 @@
#include "test_allocator.h"
#include "min_allocator.h"
-int main(int, char**) {
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
{
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = test_allocator<char>;
- using M = std::flat_multimap<int, char, C, std::vector<int, A1>, std::vector<char, A2>>;
+ using M = std::flat_multimap<int, char, C, KeyContainer<int, A1>, ValueContainer<char, A2>>;
M mo = M({{1, 1}, {1, 3}, {3, 2}}, C(5), A1(7));
M m = M({}, C(3), A1(7));
m = std::move(mo);
@@ -46,9 +47,9 @@ int main(int, char**) {
using C = test_less<int>;
using A1 = other_allocator<int>;
using A2 = other_allocator<char>;
- using M = std::flat_multimap<int, char, C, std::deque<int, A1>, std::deque<char, A2>>;
+ using M = std::flat_multimap<int, char, C, KeyContainer<int, A1>, ValueContainer<char, A2>>;
M mo = M({{4, 5}, {4, 4}}, C(5), A1(7));
- M m = M({{1, 1}, {1, 2}, {1, 3}, {4, 4}}, C(3), A1(7));
+ M m = M({{1, 1}, {2, 2}, {3, 3}, {4, 4}}, C(3), A1(7));
m = std::move(mo);
assert((m == M{{4, 5}, {4, 4}}));
assert(m.key_comp() == C(5));
@@ -59,9 +60,9 @@ int main(int, char**) {
}
{
using A = min_allocator<int>;
- using M = std::flat_multimap<int, int, std::greater<int>, std::vector<int, A>, std::vector<int, A>>;
+ using M = std::flat_multimap<int, int, std::greater<int>, KeyContainer<int, A>, ValueContainer<int, A>>;
M mo = M({{5, 1}, {5, 2}, {3, 3}}, A());
- M m = M({{4, 4}, {4, 3}, {4, 2}, {1, 1}}, A());
+ M m = M({{4, 4}, {3, 3}, {2, 2}, {1, 1}}, A());
m = std::move(mo);
assert((m == M{{5, 1}, {5, 2}, {3, 3}}));
auto [ks, vs] = std::move(m).extract();
@@ -69,6 +70,26 @@ int main(int, char**) {
assert(vs.get_allocator() == A());
assert(mo.empty());
}
+}
- return 0;
+constexpr bool test() {
+ test<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque, std::deque>();
+ }
+
+ return true;
}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
+ return 0;
+} \ No newline at end of file
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_clears.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_clears.pass.cpp
index bc65dca..ce77ab06 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_clears.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_clears.pass.cpp
@@ -16,6 +16,7 @@
#include <algorithm>
#include <cassert>
#include <compare>
+#include <deque>
#include <flat_map>
#include <functional>
#include <utility>
@@ -27,9 +28,9 @@
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) {
+ constexpr MoveNegates(int v) : value_(v) {}
+ constexpr MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; }
+ constexpr MoveNegates& operator=(MoveNegates&& rhs) {
value_ = rhs.value_;
rhs.value_ = -rhs.value_;
return *this;
@@ -41,9 +42,9 @@ struct MoveNegates {
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) {
+ constexpr MoveClears(int v) : value_(v) {}
+ constexpr MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; }
+ constexpr MoveClears& operator=(MoveClears&& rhs) {
value_ = rhs.value_;
rhs.value_ = 0;
return *this;
@@ -52,34 +53,39 @@ struct MoveClears {
auto operator<=>(const MoveClears&) const = default;
};
-int main(int, char**) {
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
+ auto value_eq = [](auto&& p, auto&& q) { return p.first == q.first; };
{
const std::pair<int, int> expected[] = {{1, 1}, {1, 2}, {3, 3}, {3, 4}, {5, 5}, {6, 6}, {7, 7}, {8, 8}};
- using M = std::flat_multimap<MoveNegates, int, std::less<MoveNegates>, std::vector<MoveNegates>>;
- M m = M(expected, expected + 8);
- M m2 = M(expected, expected + 3);
+ using M =
+ std::flat_multimap<MoveNegates, int, std::less<MoveNegates>, KeyContainer<MoveNegates>, ValueContainer<int>>;
+ M m = M(std::sorted_equivalent, 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());
- check_invariant(m);
+ assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); // still sorted
+ assert(std::adjacent_find(m.begin(), m.end(), value_eq) == m.end()); // still contains no duplicates
m.insert({1, 1});
m.insert({2, 2});
assert(m.contains(1));
assert(m.find(2) != m.end());
}
{
- const std::pair<int, int> expected[] = {{1, 1}, {1, 2}, {3, 3}, {4, 4}, {5, 5}, {5, 6}, {7, 7}, {8, 8}};
- using M = std::flat_multimap<MoveClears, int, std::less<MoveClears>, std::vector<MoveClears>>;
- M m = M(expected, expected + 8);
+ const std::pair<int, int> expected[] = {{1, 1}, {1, 2}, {3, 3}, {4, 4}, {4, 5}, {6, 6}, {7, 7}, {8, 8}};
+ using M = std::flat_multimap<MoveClears, int, std::less<MoveClears>, KeyContainer<MoveClears>, ValueContainer<int>>;
+ M m = M(std::sorted_equivalent, 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());
- check_invariant(m);
+ assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); // still sorted
+ assert(std::adjacent_find(m.begin(), m.end(), value_eq) == m.end()); // still contains no duplicates
m.insert({1, 1});
m.insert({2, 2});
assert(m.contains(1));
@@ -87,15 +93,36 @@ int main(int, char**) {
}
{
// moved-from object maintains invariant if one of underlying container does not clear after move
- using M = std::flat_multimap<int, int, std::less<>, std::vector<int>, CopyOnlyVector<int>>;
- M m1 = M({1, 1, 3}, {1, 2, 3});
- M m2 = M({1, 1}, {1, 2});
+ using M = std::flat_multimap<int, int, std::less<>, KeyContainer<int>, CopyOnlyVector<int>>;
+ M m1 = M({1, 1, 2, 3}, {1, 1, 2, 3});
+ M m2 = M({1, 2, 2}, {1, 2, 2});
m2 = std::move(m1);
- assert(m2.size() == 3);
+ assert(m2.size() == 4);
check_invariant(m1);
LIBCPP_ASSERT(m1.empty());
LIBCPP_ASSERT(m1.keys().size() == 0);
LIBCPP_ASSERT(m1.values().size() == 0);
}
+}
+
+constexpr bool test() {
+ test<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque, std::deque>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_noexcept.compile.pass.cpp
index 4eb5831..1aa4075 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_noexcept.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_noexcept.compile.pass.cpp
@@ -49,7 +49,7 @@ struct MoveThrowsComp {
bool operator()(const auto&, const auto&) const;
};
-int main(int, char**) {
+void test() {
{
using C = std::flat_multimap<int, int>;
LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v<C>);
@@ -105,6 +105,4 @@ int main(int, char**) {
using C = std::flat_multimap<int, int, std::less<int>, std::vector<int>, std::pmr::vector<int>>;
static_assert(!std::is_nothrow_move_assignable_v<C>);
}
-
- return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/range.pass.cpp
index de750e2..0b36551 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/range.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/range.pass.cpp
@@ -27,9 +27,11 @@
#include <vector>
#include "min_allocator.h"
+#include "MinSequenceContainer.h"
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
+#include "../helpers.h"
#include "../../../test_compare.h"
// test constraint container-compatible-range
@@ -66,70 +68,34 @@ static_assert(std::is_constructible_v<Map,
static_assert(!std::is_constructible_v<Map, std::from_range_t, RangeOf<int>, std::less<int>, std::allocator<int>>);
static_assert(!std::is_constructible_v<Map, std::from_range_t, RangeOf<double>, std::less<int>, std::allocator<int>>);
-int main(int, char**) {
- {
- // The constructors in this subclause shall not participate in overload
- // resolution unless uses_allocator_v<key_container_type, Alloc> is true
- // and uses_allocator_v<mapped_container_type, Alloc> is true.
-
- using C = test_less<int>;
- using A1 = test_allocator<int>;
- using A2 = other_allocator<int>;
- using V1 = std::vector<int, A1>;
- using V2 = std::vector<int, A2>;
- using M1 = std::flat_multimap<int, int, C, V1, V1>;
- using M2 = std::flat_multimap<int, int, C, V1, V2>;
- using M3 = std::flat_multimap<int, int, C, V2, V1>;
- static_assert(std::is_constructible_v<M1, std::from_range_t, M1, const A1&>);
- static_assert(!std::is_constructible_v<M1, std::from_range_t, M1, const A2&>);
- static_assert(!std::is_constructible_v<M2, std::from_range_t, M2, const A2&>);
- static_assert(!std::is_constructible_v<M3, std::from_range_t, M3, const A2&>);
-
- static_assert(std::is_constructible_v<M1, std::from_range_t, M1, const C&, const A1&>);
- static_assert(!std::is_constructible_v<M1, std::from_range_t, M1, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M2, std::from_range_t, M2, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M3, std::from_range_t, M3, const C&, const A2&>);
- }
- {
- // container-compatible-range
- using C = test_less<int>;
- using A1 = test_allocator<int>;
- using A2 = test_allocator<std::string>;
- using M = std::flat_multimap<int, std::string, C, std::vector<int, A1>, std::vector<std::string, A2>>;
- using Pair = std::pair<int, std::string>;
- using PairLike = std::tuple<int, std::string>;
- using NonPairLike = int;
-
- static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<Pair>&>);
- static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<PairLike>&>);
- static_assert(!std::is_constructible_v<M, std::from_range_t, std::vector<NonPairLike>&>);
-
- static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<Pair>&, const C&>);
- static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<PairLike>&, const C&>);
- static_assert(!std::is_constructible_v<M, std::from_range_t, std::vector<NonPairLike>&, const C&>);
-
- static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<Pair>&, const A1&>);
- static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<PairLike>&, const A1&>);
- static_assert(!std::is_constructible_v<M, std::from_range_t, std::vector<NonPairLike>&, const A1&>);
-
- static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<Pair>&, const C&, const A1&>);
- static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<PairLike>&, const C&, const A1&>);
- static_assert(!std::is_constructible_v<M, std::from_range_t, std::vector<NonPairLike>&, const C&, const A1&>);
- }
-
- using P = std::pair<int, short>;
- P ar[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {2, 7}, {3, 8}, {3, 9}};
- P expected[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {2, 7}, {3, 6}, {3, 8}, {3, 9}};
+template <class KeyContainer, class ValueContainer>
+constexpr void test() {
+ using Key = typename KeyContainer::value_type;
+ using Value = typename ValueContainer::value_type;
+ using P = std::pair<Key, Value>;
+ P ar[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {2, 7}, {3, 8}, {3, 9}};
{
// flat_multimap(from_range_t, R&&)
// input_range && !common
- using M = std::flat_multimap<int, short>;
+ using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
using Iter = cpp20_input_iterator<const P*>;
using Sent = sentinel_wrapper<Iter>;
using R = std::ranges::subrange<Iter, Sent>;
auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9))));
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<Value>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
// explicit(false)
M m2 = {std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))};
@@ -138,31 +104,67 @@ int main(int, char**) {
{
// flat_multimap(from_range_t, R&&)
// greater
- using M = std::flat_multimap<int, short, std::greater<int>, std::deque<int, min_allocator<int>>, std::deque<short>>;
+ using M = std::flat_multimap<Key, Value, std::greater<int>, KeyContainer, ValueContainer>;
using Iter = cpp20_input_iterator<const P*>;
using Sent = sentinel_wrapper<Iter>;
using R = std::ranges::subrange<Iter, Sent>;
auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9))));
- assert((m.keys() == std::deque<int, min_allocator<int>>{3, 3, 3, 2, 2, 2, 1, 1, 1}));
- LIBCPP_ASSERT((m.values() == std::deque<short>{6, 8, 9, 4, 5, 7, 1, 2, 3}));
+ assert(std::ranges::equal(m.keys(), KeyContainer{3, 3, 3, 2, 2, 2, 1, 1, 1}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<Value>>{
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ });
}
{
// flat_multimap(from_range_t, R&&)
// contiguous range
- using M = std::flat_multimap<int, short>;
+ using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
using R = std::ranges::subrange<const P*>;
auto m = M(std::from_range, R(ar, ar + 9));
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<Value>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
}
{
// flat_multimap(from_range_t, R&&, const key_compare&)
using C = test_less<int>;
- using M = std::flat_multimap<int, short, C, std::vector<int>, std::deque<short>>;
+ using M = std::flat_multimap<Key, Value, C, KeyContainer, ValueContainer>;
using R = std::ranges::subrange<const P*>;
auto m = M(std::from_range, R(ar, ar + 9), C(3));
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<Value>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.key_comp() == C(3));
// explicit(false)
@@ -170,15 +172,33 @@ int main(int, char**) {
assert(m2 == m);
assert(m2.key_comp() == C(3));
}
+}
+
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test_alloc() {
+ using P = std::pair<int, short>;
+ P ar[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {2, 7}, {3, 8}, {3, 9}};
{
// flat_multimap(from_range_t, R&&, const Allocator&)
using A1 = test_allocator<int>;
using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, std::less<int>, std::vector<int, A1>, std::deque<short, A2>>;
+ using M = std::flat_multimap<int, short, std::less<int>, KeyContainer<int, A1>, ValueContainer<short, A2>>;
using R = std::ranges::subrange<const P*>;
auto m = M(std::from_range, R(ar, ar + 9), A1(5));
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer<int, A1>{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<short>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
}
@@ -187,11 +207,23 @@ int main(int, char**) {
// explicit(false)
using A1 = test_allocator<int>;
using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, std::less<int>, std::vector<int, A1>, std::deque<short, A2>>;
+ using M = std::flat_multimap<int, short, std::less<int>, KeyContainer<int, A1>, ValueContainer<short, A2>>;
using R = std::ranges::subrange<const P*>;
M m = {std::from_range, R(ar, ar + 9), A1(5)}; // implicit ctor
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer<int, A1>{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<short>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
}
@@ -200,11 +232,23 @@ int main(int, char**) {
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, C, std::vector<int, A1>, std::deque<short, A2>>;
+ using M = std::flat_multimap<int, short, C, KeyContainer<int, A1>, ValueContainer<short, A2>>;
using R = std::ranges::subrange<const P*>;
auto m = M(std::from_range, R(ar, ar + 9), C(3), A1(5));
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer<int, A1>{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<short>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.key_comp() == C(3));
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
@@ -214,14 +258,101 @@ int main(int, char**) {
// explicit(false)
using A1 = test_allocator<int>;
using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, std::less<int>, std::deque<int, A1>, std::vector<short, A2>>;
+ using M = std::flat_multimap<int, short, std::less<int>, KeyContainer<int, A1>, ValueContainer<short, A2>>;
using R = std::ranges::subrange<const P*>;
M m = {std::from_range, R(ar, ar + 9), {}, A2(5)}; // implicit ctor
- assert(std::ranges::equal(m.keys(), expected | std::views::elements<0>));
- LIBCPP_ASSERT(std::ranges::equal(m, expected));
+ assert(std::ranges::equal(m.keys(), KeyContainer<int, A1>{1, 1, 1, 2, 2, 2, 3, 3, 3}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<short>>{
+ {1, 2, 3},
+ {1, 2, 3},
+ {1, 2, 3},
+ {4, 5, 7},
+ {4, 5, 7},
+ {4, 5, 7},
+ {6, 8, 9},
+ {6, 8, 9},
+ {6, 8, 9},
+ });
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
}
+}
+
+constexpr bool test() {
+ {
+ // The constructors in this subclause shall not participate in overload
+ // resolution unless uses_allocator_v<key_container_type, Alloc> is true
+ // and uses_allocator_v<mapped_container_type, Alloc> is true.
+
+ using C = test_less<int>;
+ using A1 = test_allocator<int>;
+ using A2 = other_allocator<int>;
+ using V1 = std::vector<int, A1>;
+ using V2 = std::vector<int, A2>;
+ using M1 = std::flat_multimap<int, int, C, V1, V1>;
+ using M2 = std::flat_multimap<int, int, C, V1, V2>;
+ using M3 = std::flat_multimap<int, int, C, V2, V1>;
+ static_assert(std::is_constructible_v<M1, std::from_range_t, M1, const A1&>);
+ static_assert(!std::is_constructible_v<M1, std::from_range_t, M1, const A2&>);
+ static_assert(!std::is_constructible_v<M2, std::from_range_t, M2, const A2&>);
+ static_assert(!std::is_constructible_v<M3, std::from_range_t, M3, const A2&>);
+
+ static_assert(std::is_constructible_v<M1, std::from_range_t, M1, const C&, const A1&>);
+ static_assert(!std::is_constructible_v<M1, std::from_range_t, M1, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M2, std::from_range_t, M2, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M3, std::from_range_t, M3, const C&, const A2&>);
+ }
+ {
+ // container-compatible-range
+ using C = test_less<int>;
+ using A1 = test_allocator<int>;
+ using A2 = test_allocator<std::string>;
+ using M = std::flat_multimap<int, std::string, C, std::vector<int, A1>, std::vector<std::string, A2>>;
+ using Pair = std::pair<int, std::string>;
+ using PairLike = std::tuple<int, std::string>;
+ using NonPairLike = int;
+
+ static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<Pair>&>);
+ static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<PairLike>&>);
+ static_assert(!std::is_constructible_v<M, std::from_range_t, std::vector<NonPairLike>&>);
+
+ static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<Pair>&, const C&>);
+ static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<PairLike>&, const C&>);
+ static_assert(!std::is_constructible_v<M, std::from_range_t, std::vector<NonPairLike>&, const C&>);
+
+ static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<Pair>&, const A1&>);
+ static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<PairLike>&, const A1&>);
+ static_assert(!std::is_constructible_v<M, std::from_range_t, std::vector<NonPairLike>&, const A1&>);
+
+ static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<Pair>&, const C&, const A1&>);
+ static_assert(std::is_constructible_v<M, std::from_range_t, std::vector<PairLike>&, const C&, const A1&>);
+ static_assert(!std::is_constructible_v<M, std::from_range_t, std::vector<NonPairLike>&, const C&, const A1&>);
+ }
+
+ test<std::vector<int>, std::vector<int>>();
+ test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
+ test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
+
+ test_alloc<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque<int>, std::vector<double>>();
+ test_alloc<std::deque, std::deque>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_container.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_container.pass.cpp
index 16579f0..b07f8ba 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_container.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_container.pass.cpp
@@ -21,6 +21,7 @@
// const mapped_container_type& mapped_cont,
// const key_compare& comp, const Alloc& a);
+#include <algorithm>
#include <deque>
#include <flat_map>
#include <functional>
@@ -31,46 +32,25 @@
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
+#include "../helpers.h"
#include "../../../test_compare.h"
-int main(int, char**) {
- {
- // The constructors in this subclause shall not participate in overload
- // resolution unless uses_allocator_v<key_container_type, Alloc> is true
- // and uses_allocator_v<mapped_container_type, Alloc> is true.
-
- using C = test_less<int>;
- using A1 = test_allocator<int>;
- using A2 = other_allocator<int>;
- using V1 = std::vector<int, A1>;
- using V2 = std::vector<int, A2>;
- using M1 = std::flat_multimap<int, int, C, V1, V1>;
- using M2 = std::flat_multimap<int, int, C, V1, V2>;
- using M3 = std::flat_multimap<int, int, C, V2, V1>;
- static_assert(std::is_constructible_v<M1, std::sorted_equivalent_t, const V1&, const V1&, const A1&>);
- static_assert(!std::is_constructible_v<M1, std::sorted_equivalent_t, const V1&, const V1&, const A2&>);
- static_assert(!std::is_constructible_v<M2, std::sorted_equivalent_t, const V1&, const V2&, const A2&>);
- static_assert(!std::is_constructible_v<M3, std::sorted_equivalent_t, const V2&, const V1&, const A2&>);
-
- static_assert(std::is_constructible_v<M1, std::sorted_equivalent_t, const V1&, const V1&, const C&, const A1&>);
- static_assert(!std::is_constructible_v<M1, std::sorted_equivalent_t, const V1&, const V1&, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M2, std::sorted_equivalent_t, const V1&, const V2&, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M3, std::sorted_equivalent_t, const V2&, const V1&, const C&, const A2&>);
- }
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
{
// flat_multimap(sorted_equivalent_t, key_container_type , mapped_container_type)
- using M = std::flat_multimap<int, char>;
- std::vector<int> ks = {1, 4, 4, 10};
- std::vector<char> vs = {4, 3, 2, 1};
- auto ks2 = ks;
- auto vs2 = vs;
+ using M = std::flat_multimap<int, char, std::less<int>, KeyContainer<int>, ValueContainer<char>>;
+ KeyContainer<int> ks = {1, 4, 4, 10};
+ ValueContainer<char> vs = {4, 3, 2, 1};
+ auto ks2 = ks;
+ auto vs2 = vs;
auto m = M(std::sorted_equivalent, ks, vs);
- assert((m == M{{1, 4}, {4, 3}, {4, 2}, {10, 1}}));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, char>>{{1, 4}, {4, 3}, {4, 2}, {10, 1}}));
m = M(std::sorted_equivalent, std::move(ks), std::move(vs));
assert(ks.empty()); // it was moved-from
assert(vs.empty()); // it was moved-from
- assert((m == M{{1, 4}, {4, 3}, {4, 2}, {10, 1}}));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, char>>{{1, 4}, {4, 3}, {4, 2}, {10, 1}}));
// explicit(false)
M m2 = {std::sorted_equivalent, std::move(ks2), std::move(vs2)};
@@ -79,41 +59,41 @@ int main(int, char**) {
{
// flat_multimap(sorted_equivalent_t, key_container_type , mapped_container_type)
// non-default container, comparator and allocator type
- using Ks = std::deque<int, min_allocator<int>>;
- using Vs = std::deque<char, min_allocator<char>>;
+ using Ks = KeyContainer<int, min_allocator<int>>;
+ using Vs = ValueContainer<char, min_allocator<char>>;
using M = std::flat_multimap<int, char, std::greater<int>, Ks, Vs>;
- Ks ks = {10, 1, 1, 1};
+ Ks ks = {10, 4, 4, 1};
Vs vs = {1, 2, 3, 4};
auto m = M(std::sorted_equivalent, ks, vs);
- assert((m == M{{1, 2}, {1, 3}, {1, 4}, {10, 1}}));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, char>>{{10, 1}, {4, 2}, {4, 3}, {1, 4}}));
m = M(std::sorted_equivalent, std::move(ks), std::move(vs));
assert(ks.empty()); // it was moved-from
assert(vs.empty()); // it was moved-from
- assert((m == M{{1, 2}, {1, 3}, {1, 4}, {10, 1}}));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, char>>{{10, 1}, {4, 2}, {4, 3}, {1, 4}}));
}
{
// flat_multimap(sorted_equivalent_t, key_container_type , mapped_container_type)
// allocator copied into the containers
using A = test_allocator<int>;
- using M = std::flat_multimap<int, int, std::less<int>, std::vector<int, A>, std::deque<int, A>>;
- auto ks = std::vector<int, A>({2, 2, 4, 10}, A(4));
- auto vs = std::deque<int, A>({4, 3, 2, 1}, A(5));
+ using M = std::flat_multimap<int, int, std::less<int>, KeyContainer<int, A>, ValueContainer<int, A>>;
+ auto ks = KeyContainer<int, A>({1, 4, 4, 10}, A(4));
+ auto vs = ValueContainer<int, A>({4, 3, 2, 1}, A(5));
auto m = M(std::sorted_equivalent, std::move(ks), std::move(vs));
assert(ks.empty()); // it was moved-from
assert(vs.empty()); // it was moved-from
- assert((m == M{{2, 4}, {2, 3}, {4, 2}, {10, 1}}));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, char>>{{1, 4}, {4, 3}, {4, 2}, {10, 1}}));
assert(m.keys().get_allocator() == A(4));
assert(m.values().get_allocator() == A(5));
}
{
// flat_multimap(sorted_equivalent_t, key_container_type , mapped_container_type, key_compare)
- using C = test_less<int>;
- using M = std::flat_multimap<int, char, C>;
- std::vector<int> ks = {1, 2, 10, 10};
- std::vector<char> vs = {4, 3, 2, 1};
+ using C = test_less<int>;
+ using M = std::flat_multimap<int, char, C, KeyContainer<int>, ValueContainer<char>>;
+ KeyContainer<int> ks = {1, 4, 4, 10};
+ ValueContainer<char> vs = {4, 3, 2, 1};
auto m = M(std::sorted_equivalent, ks, vs, C(4));
- assert((m == M{{1, 4}, {2, 3}, {10, 2}, {10, 1}}));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, char>>{{1, 4}, {4, 3}, {4, 2}, {10, 1}}));
assert(m.key_comp() == C(4));
// explicit(false)
@@ -123,19 +103,19 @@ int main(int, char**) {
}
{
// flat_multimap(sorted_equivalent_t, key_container_type , mapped_container_type, key_compare, const Allocator&)
- using C = test_less<int>;
- using A = test_allocator<int>;
- using M = std::flat_multimap<int, int, C, std::vector<int, A>, std::vector<int, A>>;
- std::vector<int, A> ks = {1, 2, 4, 10};
- std::vector<int, A> vs = {4, 3, 2, 1};
- auto m = M(std::sorted_equivalent, ks, vs, C(4), A(5));
- assert((m == M{{1, 4}, {2, 3}, {4, 2}, {10, 1}}));
+ using C = test_less<int>;
+ using A = test_allocator<int>;
+ using M = std::flat_multimap<int, int, C, KeyContainer<int, A>, ValueContainer<int, A>>;
+ KeyContainer<int, A> ks = {1, 4, 4, 10};
+ ValueContainer<int, A> vs = {4, 3, 2, 1};
+ auto m = M(std::sorted_equivalent, ks, vs, C(4), A(5));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, char>>{{1, 4}, {4, 3}, {4, 2}, {10, 1}}));
assert(m.key_comp() == C(4));
assert(m.keys().get_allocator() == A(5));
assert(m.values().get_allocator() == A(5));
// explicit(false)
- M m2 = {ks, vs, C(4), A(5)};
+ M m2 = {std::sorted_equivalent, ks, vs, C(4), A(5)};
assert(m2 == m);
assert(m2.key_comp() == C(4));
assert(m2.keys().get_allocator() == A(5));
@@ -144,13 +124,13 @@ int main(int, char**) {
{
// flat_multimap(sorted_equivalent_t, key_container_type , mapped_container_type, const Allocator&)
using A = test_allocator<int>;
- using M = std::flat_multimap<int, int, std::less<int>, std::vector<int, A>, std::deque<int, A>>;
- auto ks = std::vector<int, A>({1, 2, 4, 4}, A(4));
- auto vs = std::deque<int, A>({4, 3, 2, 1}, A(5));
+ using M = std::flat_multimap<int, int, std::less<int>, KeyContainer<int, A>, ValueContainer<int, A>>;
+ auto ks = KeyContainer<int, A>({1, 4, 4, 10}, A(4));
+ auto vs = ValueContainer<int, A>({4, 3, 2, 1}, A(5));
auto m = M(std::sorted_equivalent, ks, vs, A(6)); // replaces the allocators
assert(!ks.empty()); // it was an lvalue above
assert(!vs.empty()); // it was an lvalue above
- assert((m == M{{1, 4}, {2, 3}, {4, 2}, {4, 1}}));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, char>>{{1, 4}, {4, 3}, {4, 2}, {10, 1}}));
assert(m.keys().get_allocator() == A(6));
assert(m.values().get_allocator() == A(6));
@@ -160,6 +140,51 @@ int main(int, char**) {
assert(m2.keys().get_allocator() == A(6));
assert(m2.values().get_allocator() == A(6));
}
+}
+
+constexpr bool test() {
+ {
+ // The constructors in this subclause shall not participate in overload
+ // resolution unless uses_allocator_v<key_container_type, Alloc> is true
+ // and uses_allocator_v<mapped_container_type, Alloc> is true.
+
+ using C = test_less<int>;
+ using A1 = test_allocator<int>;
+ using A2 = other_allocator<int>;
+ using V1 = std::vector<int, A1>;
+ using V2 = std::vector<int, A2>;
+ using M1 = std::flat_multimap<int, int, C, V1, V1>;
+ using M2 = std::flat_multimap<int, int, C, V1, V2>;
+ using M3 = std::flat_multimap<int, int, C, V2, V1>;
+ static_assert(std::is_constructible_v<M1, std::sorted_equivalent_t, const V1&, const V1&, const A1&>);
+ static_assert(!std::is_constructible_v<M1, std::sorted_equivalent_t, const V1&, const V1&, const A2&>);
+ static_assert(!std::is_constructible_v<M2, std::sorted_equivalent_t, const V1&, const V2&, const A2&>);
+ static_assert(!std::is_constructible_v<M3, std::sorted_equivalent_t, const V2&, const V1&, const A2&>);
+
+ static_assert(std::is_constructible_v<M1, std::sorted_equivalent_t, const V1&, const V1&, const C&, const A1&>);
+ static_assert(!std::is_constructible_v<M1, std::sorted_equivalent_t, const V1&, const V1&, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M2, std::sorted_equivalent_t, const V1&, const V2&, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M3, std::sorted_equivalent_t, const V2&, const V1&, const C&, const A2&>);
+ }
+
+ test<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque, std::vector>();
+ test<std::deque, std::deque>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_initializer_list.pass.cpp
index b34313b..555b8d4 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_initializer_list.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_initializer_list.pass.cpp
@@ -19,9 +19,11 @@
// flat_multimap(sorted_equivalent_t, initializer_list<value_type> il,
// const key_compare& comp, const Alloc& a);
+#include <algorithm>
#include <deque>
#include <flat_map>
#include <functional>
+#include <type_traits>
#include <vector>
#include "min_allocator.h"
@@ -31,13 +33,86 @@
#include "../../../test_compare.h"
template <class T, class U>
-std::initializer_list<std::pair<T, U>> il = {{1, 1}, {4, 2}, {4, 4}, {5, 5}};
+constexpr std::initializer_list<std::pair<T, U>> il = {{1, 4}, {4, 2}, {4, 4}, {5, 5}};
-const auto il1 = il<int, int>;
-const auto il2 = il<int, short>;
-const auto il3 = il<short, int>;
+constexpr auto il1 = il<int, int>;
+constexpr auto il2 = il<int, short>;
+constexpr auto il3 = il<short, int>;
-int main(int, char**) {
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test() {
+ {
+ // flat_multimap(sorted_equivalent_t, initializer_list<value_type>);
+ using M = std::flat_multimap<int, int, std::less<int>, KeyContainer<int>, ValueContainer<int>>;
+ auto m = M(std::sorted_equivalent, il1);
+ assert(std::ranges::equal(m, std::vector<std::pair<int, int>>{{1, 4}, {4, 2}, {4, 4}, {5, 5}}));
+
+ // explicit(false)
+ M m2 = {std::sorted_equivalent, il1};
+ assert(m2 == m);
+ }
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ // flat_multimap(sorted_equivalent_t, initializer_list<value_type>, const key_compare&);
+ using M = std::flat_multimap<int, int, std::function<bool(int, int)>, KeyContainer<int>, ValueContainer<int>>;
+ auto m = M(std::sorted_equivalent, il1, std::less<int>());
+ assert(std::ranges::equal(m, std::vector<std::pair<int, int>>{{1, 4}, {4, 2}, {4, 4}, {5, 5}}));
+ assert(m.key_comp()(1, 2) == true);
+
+ // explicit(false)
+ M m2 = {std::sorted_equivalent, il1, std::less<int>()};
+ assert(m2 == m);
+ }
+ {
+ // flat_multimap(sorted_equivalent_t, initializer_list<value_type>, const key_compare&);
+ // greater
+ using M =
+ std::flat_multimap<int, int, std::greater<int>, KeyContainer<int, min_allocator<int>>, ValueContainer<int>>;
+ std::initializer_list<std::pair<int, int>> il4{{5, 5}, {4, 5}, {4, 2}, {1, 1}};
+ auto m = M(std::sorted_equivalent, il4, std::greater<int>());
+ assert(std::ranges::equal(m, std::vector<std::pair<int, int>>{{5, 5}, {4, 5}, {4, 2}, {1, 1}}));
+ }
+ {
+ // flat_multimap(sorted_equivalent_t, initializer_list<value_type>, const Allocator&)
+ using A1 = test_allocator<int>;
+ using A2 = test_allocator<short>;
+ using M = std::flat_multimap<int, short, std::less<int>, KeyContainer<int, A1>, ValueContainer<short, A2>>;
+ auto m = M(std::sorted_equivalent, il2, A1(5));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, short>>{{1, 4}, {4, 2}, {4, 4}, {5, 5}}));
+ assert(m.keys().get_allocator() == A1(5));
+ assert(m.values().get_allocator() == A2(5));
+
+ // explicit(false)
+ M m2 = {std::sorted_equivalent, il2, A1(5)};
+ assert(m2 == m);
+ assert(m2.keys().get_allocator() == A1(5));
+ assert(m2.values().get_allocator() == A2(5));
+ }
+ {
+ // flat_multimap(sorted_equivalent_t, initializer_list<value_type>, const key_compare&, const Allocator&);
+ using C = test_less<int>;
+ using A1 = test_allocator<int>;
+ using A2 = test_allocator<short>;
+ using M = std::flat_multimap<int, short, C, KeyContainer<int, A1>, ValueContainer<short, A2>>;
+ auto m = M(std::sorted_equivalent, il2, C(3), A1(5));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, short>>{{1, 4}, {4, 2}, {4, 4}, {5, 5}}));
+ assert(m.key_comp() == C(3));
+ assert(m.keys().get_allocator() == A1(5));
+ assert(m.values().get_allocator() == A2(5));
+ }
+ {
+ // flat_multimap(sorted_equivalent_t, initializer_list<value_type>, const key_compare&, const Allocator&);
+ // explicit(false)
+ using A1 = test_allocator<short>;
+ using A2 = test_allocator<int>;
+ using M = std::flat_multimap<short, int, std::less<int>, KeyContainer<short, A1>, ValueContainer<int, A2>>;
+ M m = {std::sorted_equivalent, il3, {}, A1(5)}; // implicit ctor
+ assert(std::ranges::equal(m, std::vector<std::pair<short, int>>{{1, 4}, {4, 2}, {4, 4}, {5, 5}}));
+ assert(m.keys().get_allocator() == A1(5));
+ assert(m.values().get_allocator() == A2(5));
+ }
+}
+
+constexpr bool test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<key_container_type, Alloc> is true
@@ -108,76 +183,23 @@ int main(int, char**) {
std::allocator<int>>);
}
- {
- // flat_multimap(sorted_equivalent_t, initializer_list<value_type>);
- using M = std::flat_multimap<int, int>;
- auto m = M(std::sorted_equivalent, il1);
- auto expected = M{{1, 1}, {4, 2}, {4, 4}, {5, 5}};
- assert(m == expected);
-
- // explicit(false)
- M m2 = {std::sorted_equivalent, il1};
- assert(m2 == m);
- }
- {
- // flat_multimap(sorted_equivalent_t, initializer_list<value_type>, const key_compare&);
- using M = std::flat_multimap<int, int, std::function<bool(int, int)>>;
- auto m = M(std::sorted_equivalent, il1, std::less<int>());
- assert(m == M({{1, 1}, {4, 2}, {4, 4}, {5, 5}}, std::less<>()));
- assert(m.key_comp()(1, 2) == true);
+ test<std::vector, std::vector>();
- // explicit(false)
- M m2 = {std::sorted_equivalent, il1, std::less<int>()};
- assert(m2 == m);
- }
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
{
- // flat_multimap(sorted_equivalent_t, initializer_list<value_type>, const key_compare&);
- // greater
- using M = std::flat_multimap<int, int, std::greater<int>, std::deque<int, min_allocator<int>>, std::vector<int>>;
- std::initializer_list<std::pair<int, int>> il4{{5, 5}, {4, 4}, {1, 2}, {1, 1}};
- auto m = M(std::sorted_equivalent, il4, std::greater<int>());
- assert((m == M{{5, 5}, {4, 4}, {1, 2}, {1, 1}}));
+ test<std::deque, std::deque>();
}
- {
- // flat_multimap(sorted_equivalent_t, initializer_list<value_type>, const Allocator&)
- using A1 = test_allocator<int>;
- using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, std::less<int>, std::vector<int, A1>, std::deque<short, A2>>;
- auto m = M(std::sorted_equivalent, il2, A1(5));
- auto expected = M{{1, 1}, {4, 2}, {4, 4}, {5, 5}};
- assert(m == expected);
- assert(m.keys().get_allocator() == A1(5));
- assert(m.values().get_allocator() == A2(5));
- // explicit(false)
- M m2 = {std::sorted_equivalent, il2, A1(5)};
- assert(m2 == m);
- assert(m2.keys().get_allocator() == A1(5));
- assert(m2.values().get_allocator() == A2(5));
- }
- {
- // flat_multimap(sorted_equivalent_t, initializer_list<value_type>, const key_compare&, const Allocator&);
- using C = test_less<int>;
- using A1 = test_allocator<int>;
- using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, C, std::vector<int, A1>, std::deque<short, A2>>;
- auto m = M(std::sorted_equivalent, il2, C(3), A1(5));
- assert((m == M{{1, 1}, {4, 2}, {4, 4}, {5, 5}}));
- assert(m.key_comp() == C(3));
- assert(m.keys().get_allocator() == A1(5));
- assert(m.values().get_allocator() == A2(5));
- }
- {
- // flat_multimap(sorted_equivalent_t, initializer_list<value_type>, const key_compare&, const Allocator&);
- // explicit(false)
- using A1 = test_allocator<short>;
- using A2 = test_allocator<int>;
- using M = std::flat_multimap<short, int, std::less<int>, std::deque<short, A1>, std::vector<int, A2>>;
- M m = {std::sorted_equivalent, il3, {}, A1(5)}; // implicit ctor
- assert((m == M{{1, 1}, {4, 2}, {4, 4}, {5, 5}}));
- assert(m.keys().get_allocator() == A1(5));
- assert(m.values().get_allocator() == A2(5));
- }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_iter_iter.pass.cpp
index 45c4b3d..72e9695 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_iter_iter.pass.cpp
@@ -17,52 +17,33 @@
// template<class InputIterator, class Allocator>
// flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a);
+#include <algorithm>
#include <deque>
#include <flat_map>
#include <functional>
+#include <type_traits>
#include <vector>
+#include "MinSequenceContainer.h"
#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<key_container_type, Alloc> is true
- // and uses_allocator_v<mapped_container_type, Alloc> is true.
- using C = test_less<int>;
- using A1 = test_allocator<int>;
- using A2 = other_allocator<int>;
- using V1 = std::vector<int, A1>;
- using V2 = std::vector<int, A2>;
- using M1 = std::flat_multimap<int, int, C, V1, V1>;
- using M2 = std::flat_multimap<int, int, C, V1, V2>;
- using M3 = std::flat_multimap<int, int, C, V2, V1>;
- using Iter1 = typename M1::iterator;
- using Iter2 = typename M2::iterator;
- using Iter3 = typename M3::iterator;
- static_assert(std::is_constructible_v<M1, std::sorted_equivalent_t, Iter1, Iter1, const A1&>);
- static_assert(!std::is_constructible_v<M1, std::sorted_equivalent_t, Iter1, Iter1, const A2&>);
- static_assert(!std::is_constructible_v<M2, std::sorted_equivalent_t, Iter2, Iter2, const A2&>);
- static_assert(!std::is_constructible_v<M3, std::sorted_equivalent_t, Iter3, Iter3, const A2&>);
+template <class KeyContainer, class ValueContainer>
+constexpr void test() {
+ using Key = typename KeyContainer::value_type;
+ using Value = typename ValueContainer::value_type;
- static_assert(std::is_constructible_v<M1, std::sorted_equivalent_t, Iter1, Iter1, const C&, const A1&>);
- static_assert(!std::is_constructible_v<M1, std::sorted_equivalent_t, Iter1, Iter1, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M2, std::sorted_equivalent_t, Iter2, Iter2, const C&, const A2&>);
- static_assert(!std::is_constructible_v<M3, std::sorted_equivalent_t, Iter3, Iter3, const C&, const A2&>);
- }
{
// flat_multimap(sorted_equivalent_t, InputIterator, InputIterator);
// cpp17_input_iterator
- using M = std::flat_multimap<int, int>;
- using P = std::pair<int, int>;
- P ar[] = {{1, 1}, {4, 4}, {5, 5}, {5, 2}};
+ using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
+ using P = std::pair<Key, Value>;
+ P ar[] = {{1, 1}, {4, 2}, {4, 4}, {5, 5}};
auto m = M(std::sorted_equivalent, cpp17_input_iterator<const P*>(ar), cpp17_input_iterator<const P*>(ar + 4));
- auto expected = M{{1, 1}, {4, 4}, {5, 5}, {5, 2}};
- assert(m == expected);
+ assert(std::ranges::equal(m, std::vector<std::pair<int, int>>{{1, 1}, {4, 2}, {4, 4}, {5, 5}}));
// explicit(false)
M m2 = {std::sorted_equivalent, cpp17_input_iterator<const P*>(ar), cpp17_input_iterator<const P*>(ar + 4)};
@@ -71,25 +52,24 @@ int main(int, char**) {
{
// flat_multimap(sorted_equivalent_t, InputIterator, InputIterator);
// contiguous iterator
- using C = test_less<int>;
- using M =
- std::flat_multimap<int, int, C, std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>;
- std::pair<int, int> ar[] = {{1, 1}, {1, 4}, {2, 2}, {5, 5}};
- auto m = M(std::sorted_equivalent, ar, ar + 4);
- auto expected = M{{1, 1}, {1, 4}, {2, 2}, {5, 5}};
- assert(m == expected);
+ using C = test_less<Key>;
+ using P = std::pair<Key, Value>;
+ using M = std::flat_multimap<Key, Value, C, KeyContainer, ValueContainer>;
+ P ar[] = {{1, 1}, {4, 2}, {4, 4}, {5, 5}};
+ auto m = M(std::sorted_equivalent, ar, ar + 4);
+ assert(std::ranges::equal(m, std::vector<std::pair<int, int>>{{1, 1}, {4, 2}, {4, 4}, {5, 5}}));
}
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
// flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, const key_compare&);
// cpp_17_input_iterator
- using M = std::flat_multimap<int, int, std::function<bool(int, int)>>;
- using P = std::pair<int, int>;
- P ar[] = {{1, 1}, {2, 2}, {2, 4}, {5, 5}};
+ using M = std::flat_multimap<Key, Value, std::function<bool(Key, Value)>>;
+ using P = std::pair<Key, Value>;
+ P ar[] = {{1, 1}, {4, 2}, {4, 4}, {5, 5}};
auto m = M(std::sorted_equivalent,
cpp17_input_iterator<const P*>(ar),
cpp17_input_iterator<const P*>(ar + 4),
std::less<int>());
- assert(m == M({{1, 1}, {2, 2}, {2, 4}, {5, 5}}, std::less<>()));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, int>>{{1, 1}, {4, 2}, {4, 4}, {5, 5}}));
assert(m.key_comp()(1, 2) == true);
// explicit(false)
@@ -102,36 +82,38 @@ int main(int, char**) {
{
// flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, const key_compare&);
// greater
- using M = std::flat_multimap<int, int, std::greater<int>, std::deque<int, min_allocator<int>>, std::vector<int>>;
- using P = std::pair<int, int>;
- P ar[] = {{5, 5}, {2, 4}, {2, 2}, {1, 1}};
+ using M = std::flat_multimap<Key, Value, std::greater<int>, KeyContainer, ValueContainer>;
+ using P = std::pair<Key, Value>;
+ P ar[] = {{5, 5}, {4, 4}, {4, 2}, {1, 1}};
auto m = M(std::sorted_equivalent,
cpp17_input_iterator<const P*>(ar),
cpp17_input_iterator<const P*>(ar + 4),
std::greater<int>());
- assert((m == M{{5, 5}, {2, 4}, {2, 2}, {1, 1}}));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, int>>{{5, 5}, {4, 4}, {4, 2}, {1, 1}}));
}
{
// flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, const key_compare&);
// contiguous iterator
- using C = test_less<int>;
- using M =
- std::flat_multimap<int, int, C, std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>;
- std::pair<int, int> ar[1] = {{42, 42}};
- auto m = M(std::sorted_equivalent, ar, ar, C(5));
+ using C = test_less<Key>;
+ using M = std::flat_multimap<Key, Value, C, KeyContainer, ValueContainer>;
+ std::pair<Key, Value> ar[1] = {{42, 42}};
+ auto m = M(std::sorted_equivalent, ar, ar, C(5));
assert(m.empty());
assert(m.key_comp() == C(5));
}
+}
+
+template <template <class...> class KeyContainer, template <class...> class ValueContainer>
+constexpr void test_alloc() {
{
// flat_multimap(sorted_equivalent_t, InputIterator , InputIterator, const Allocator&)
- using A1 = test_allocator<int>;
- using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, std::less<int>, std::vector<int, A1>, std::deque<short, A2>>;
- using P = std::pair<int, int>;
- P ar[] = {{2, 1}, {2, 2}, {4, 4}, {5, 5}};
- auto m = M(std::sorted_equivalent, ar, ar + 4, A1(5));
- auto expected = M{{2, 1}, {2, 2}, {4, 4}, {5, 5}};
- assert(m == expected);
+ using A1 = test_allocator<int>;
+ using A2 = test_allocator<short>;
+ using M = std::flat_multimap<int, short, std::less<int>, KeyContainer<int, A1>, ValueContainer<short, A2>>;
+ using P = std::pair<int, int>;
+ P ar[] = {{1, 1}, {4, 2}, {4, 4}, {5, 5}};
+ auto m = M(std::sorted_equivalent, ar, ar + 4, A1(5));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, int>>{{1, 1}, {4, 2}, {4, 4}, {5, 5}}));
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
@@ -146,11 +128,11 @@ int main(int, char**) {
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = test_allocator<short>;
- using M = std::flat_multimap<int, short, C, std::vector<int, A1>, std::deque<short, A2>>;
+ using M = std::flat_multimap<int, short, C, KeyContainer<int, A1>, ValueContainer<short, A2>>;
using P = std::pair<int, int>;
- P ar[] = {{1, 1}, {1, 2}, {1, 4}, {1, 5}};
+ P ar[] = {{1, 1}, {4, 2}, {4, 4}, {5, 5}};
auto m = M(std::sorted_equivalent, ar, ar + 4, C(3), A1(5));
- assert((m == M{{1, 1}, {1, 2}, {1, 4}, {1, 5}}));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, int>>{{1, 1}, {4, 2}, {4, 4}, {5, 5}}));
assert(m.key_comp() == C(3));
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
@@ -160,14 +142,67 @@ int main(int, char**) {
// explicit(false)
using A1 = test_allocator<short>;
using A2 = test_allocator<int>;
- using M = std::flat_multimap<short, int, std::less<int>, std::deque<short, A1>, std::vector<int, A2>>;
+ using M = std::flat_multimap<short, int, std::less<int>, KeyContainer<short, A1>, ValueContainer<int, A2>>;
using P = std::pair<int, int>;
- P ar[] = {{1, 1}, {1, 2}, {1, 4}, {1, 5}};
+ P ar[] = {{1, 1}, {4, 2}, {4, 4}, {5, 5}};
M m = {std::sorted_equivalent, ar, ar + 4, {}, A1(5)}; // implicit ctor
- assert((m == M{{1, 1}, {1, 2}, {1, 4}, {1, 5}}));
+ assert(std::ranges::equal(m, std::vector<std::pair<int, int>>{{1, 1}, {4, 2}, {4, 4}, {5, 5}}));
assert(m.keys().get_allocator() == A1(5));
assert(m.values().get_allocator() == A2(5));
}
+}
+
+constexpr bool test() {
+ {
+ // The constructors in this subclause shall not participate in overload
+ // resolution unless uses_allocator_v<key_container_type, Alloc> is true
+ // and uses_allocator_v<mapped_container_type, Alloc> is true.
+ using C = test_less<int>;
+ using A1 = test_allocator<int>;
+ using A2 = other_allocator<int>;
+ using V1 = std::vector<int, A1>;
+ using V2 = std::vector<int, A2>;
+ using M1 = std::flat_multimap<int, int, C, V1, V1>;
+ using M2 = std::flat_multimap<int, int, C, V1, V2>;
+ using M3 = std::flat_multimap<int, int, C, V2, V1>;
+ using Iter1 = typename M1::iterator;
+ using Iter2 = typename M2::iterator;
+ using Iter3 = typename M3::iterator;
+ static_assert(std::is_constructible_v<M1, std::sorted_equivalent_t, Iter1, Iter1, const A1&>);
+ static_assert(!std::is_constructible_v<M1, std::sorted_equivalent_t, Iter1, Iter1, const A2&>);
+ static_assert(!std::is_constructible_v<M2, std::sorted_equivalent_t, Iter2, Iter2, const A2&>);
+ static_assert(!std::is_constructible_v<M3, std::sorted_equivalent_t, Iter3, Iter3, const A2&>);
+
+ static_assert(std::is_constructible_v<M1, std::sorted_equivalent_t, Iter1, Iter1, const C&, const A1&>);
+ static_assert(!std::is_constructible_v<M1, std::sorted_equivalent_t, Iter1, Iter1, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M2, std::sorted_equivalent_t, Iter2, Iter2, const C&, const A2&>);
+ static_assert(!std::is_constructible_v<M3, std::sorted_equivalent_t, Iter3, Iter3, const C&, const A2&>);
+ }
+
+ test<std::vector<int>, std::vector<int>>();
+ test<std::vector<int>, std::vector<double>>();
+ test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
+ test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
+ test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
+
+ test_alloc<std::vector, std::vector>();
+
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque<int>, std::vector<double>>();
+ test_alloc<std::deque, std::deque>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.erasure/erase_if.pass.cpp
index 76d5cbd..bed9337 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.erasure/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.erasure/erase_if.pass.cpp
@@ -34,7 +34,7 @@ static_assert(HasStdErase<std::vector<int>>);
static_assert(!HasStdErase<std::flat_multimap<int, int>>);
template <class M>
-M make(std::initializer_list<int> vals) {
+constexpr M make(std::initializer_list<int> vals) {
M ret;
for (int v : vals) {
ret.emplace(static_cast<typename M::key_type>(v), static_cast<typename M::mapped_type>(v + 10));
@@ -43,8 +43,8 @@ M make(std::initializer_list<int> vals) {
}
template <class M, class Pred>
-void test0(
- std::initializer_list<int> vals, Pred p, std::initializer_list<int> expected, std::size_t expected_erased_count) {
+constexpr void
+test0(std::initializer_list<int> vals, Pred p, std::initializer_list<int> expected, std::size_t expected_erased_count) {
M s = make<M>(vals);
ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p)));
assert(expected_erased_count == std::erase_if(s, p));
@@ -52,7 +52,7 @@ void test0(
}
template <class S>
-void test() {
+constexpr void test() {
// Test all the plausible signatures for this predicate.
auto is1 = [](typename S::const_reference v) { return v.first == 1; };
auto is2 = [](typename S::value_type v) { return v.first == 2; };
@@ -81,7 +81,7 @@ void test() {
test0<S>({1, 2, 2, 3, 3, 3}, False, {1, 2, 2, 3, 3, 3}, 0);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::flat_multimap<int, char>>();
test<std::flat_multimap<int,
char,
@@ -89,10 +89,24 @@ int main(int, char**) {
std::vector<int, min_allocator<int>>,
std::vector<char, min_allocator<char>>>>();
test<std::flat_multimap<int, char, std::greater<int>, std::vector<int, test_allocator<int>>>>();
- test<std::flat_multimap<int, char, std::less<int>, std::deque<int, min_allocator<int>>>>();
- test<std::flat_multimap<int, char, std::greater<int>, std::deque<int, test_allocator<int>>>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::flat_multimap<int, char, std::less<int>, std::deque<int, min_allocator<int>>>>();
+ test<std::flat_multimap<int, char, std::greater<int>, std::deque<int, test_allocator<int>>>>();
+ }
test<std::flat_multimap<long, int>>();
test<std::flat_multimap<double, int>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator.pass.cpp
index c128595..66154be 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator.pass.cpp
@@ -32,7 +32,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -79,9 +79,12 @@ void test() {
assert(i > m.begin()); // operator>
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<char>>();
- test<std::deque<int>, std::vector<char>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<char>>();
test<MinSequenceContainer<int>, MinSequenceContainer<char>>();
test<std::vector<int, min_allocator<int>>, std::vector<char, min_allocator<char>>>();
@@ -101,5 +104,14 @@ int main(int, char**) {
assert(!(cii != ii1));
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_comparison.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_comparison.pass.cpp
index c2f4f60..35b51af 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_comparison.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_comparison.pass.cpp
@@ -24,7 +24,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -142,11 +142,23 @@ void test() {
assert(cri2 <=> cri1 == std::strong_ordering::greater);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<char>>();
- test<std::deque<int>, std::vector<char>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<char>>();
test<MinSequenceContainer<int>, MinSequenceContainer<char>>();
test<std::vector<int, min_allocator<int>>, std::vector<char, min_allocator<char>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/reverse_iterator.pass.cpp
index 6e29d20..623882d 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/reverse_iterator.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/reverse_iterator.pass.cpp
@@ -27,48 +27,62 @@
#include <iterator>
+#include "MinSequenceContainer.h"
#include "test_macros.h"
+#include "min_allocator.h"
-int main(int, char**) {
+template <class KeyContainer, class ValueContainer>
+constexpr void test() {
+ using Key = typename KeyContainer::value_type;
+ using Value = typename ValueContainer::value_type;
+ using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
+ M m = {{1, 'a'}, {1, 'b'}, {2, 'c'}, {2, 'd'}, {3, 'e'}, {3, 'f'}, {4, 'g'}, {4, 'h'}};
+ const M& cm = m;
+ ASSERT_SAME_TYPE(decltype(m.rbegin()), typename M::reverse_iterator);
+ ASSERT_SAME_TYPE(decltype(m.crbegin()), typename M::const_reverse_iterator);
+ ASSERT_SAME_TYPE(decltype(cm.rbegin()), typename M::const_reverse_iterator);
+ ASSERT_SAME_TYPE(decltype(m.rend()), typename M::reverse_iterator);
+ ASSERT_SAME_TYPE(decltype(m.crend()), typename M::const_reverse_iterator);
+ ASSERT_SAME_TYPE(decltype(cm.rend()), typename 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() == 8);
+ assert(std::distance(m.rbegin(), m.rend()) == 8);
+ assert(std::distance(cm.rbegin(), cm.rend()) == 8);
+ assert(std::distance(m.crbegin(), m.crend()) == 8);
+ assert(std::distance(cm.crbegin(), cm.crend()) == 8);
+ typename M::reverse_iterator i; // default-construct
+ ASSERT_SAME_TYPE(decltype(i->first), const int&);
+ ASSERT_SAME_TYPE(decltype(i->second), char&);
+ i = m.rbegin(); // move-assignment
+ typename M::const_reverse_iterator k = i; // converting constructor
+ assert(i == k); // comparison
+ for (int j = 8; j >= 1; --j, ++i) { // pre-increment
+ assert(i->first == (j + 1) / 2); // operator->
+ }
+ assert(i == m.rend());
+ for (int j = 1; j <= 8; ++j) {
+ --i; // pre-decrement
+ assert((*i).first == (j + 1) / 2);
+ }
+ assert(i == m.rbegin());
+}
+
+constexpr bool test() {
+ test<std::vector<int>, std::vector<char>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
{
- using M = std::flat_multimap<int, char, std::less<int>, std::deque<int>, std::deque<char>>;
- M m = {{1, 'a'}, {1, 'b'}, {2, 'c'}, {2, 'd'}, {3, 'e'}, {3, 'f'}, {4, 'g'}, {4, 'h'}};
- 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() == 8);
- assert(std::distance(m.rbegin(), m.rend()) == 8);
- assert(std::distance(cm.rbegin(), cm.rend()) == 8);
- assert(std::distance(m.crbegin(), m.crend()) == 8);
- assert(std::distance(cm.crbegin(), cm.crend()) == 8);
- M::reverse_iterator i; // default-construct
- ASSERT_SAME_TYPE(decltype(i->first), const int&);
- ASSERT_SAME_TYPE(decltype(i->second), char&);
- i = m.rbegin(); // move-assignment
- M::const_reverse_iterator k = i; // converting constructor
- assert(i == k); // comparison
- for (int j = 8; j >= 1; --j, ++i) { // pre-increment
- assert(i->first == (j + 1) / 2); // operator->
- assert(i->second == 'a' + j - 1);
- }
- assert(i == m.rend());
- for (int j = 1; j <= 8; ++j) {
- --i; // pre-decrement
- assert((*i).first == (j + 1) / 2);
- assert((*i).second == 'a' + j - 1);
- }
- assert(i == m.rbegin());
+ test<std::deque<int>, std::vector<char>>();
}
+ test<MinSequenceContainer<int>, MinSequenceContainer<char>>();
+ test<std::vector<int, min_allocator<int>>, std::vector<char, min_allocator<char>>>();
+
{
// N3644 testing
using C = std::flat_multimap<int, char>;
@@ -84,6 +98,14 @@ int main(int, char**) {
assert(!(ii1 != cii));
assert(!(cii != ii1));
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/clear.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/clear.pass.cpp
index 5b0788b..5f30e14 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/clear.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/clear.pass.cpp
@@ -39,7 +39,7 @@ static_assert(
#endif
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -52,13 +52,24 @@ void test() {
assert(m.size() == 0);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<int>>();
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace.pass.cpp
index 9ef0c26..ea1843d 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace.pass.cpp
@@ -41,7 +41,7 @@ static_assert(!CanEmplace<Map, Emplaceable>);
static_assert(!CanEmplace<Map, int, double>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -113,7 +113,7 @@ void test() {
}
template <class KeyContainer, class ValueContainer>
-void test_emplaceable() {
+constexpr void test_emplaceable() {
using M = std::flat_multimap<int, Emplaceable, std::less<int>, KeyContainer, ValueContainer>;
using R = typename M::iterator;
@@ -136,23 +136,38 @@ void test_emplaceable() {
assert(m.begin()->second == Emplaceable(2, 3.5));
}
-int main(int, char**) {
+constexpr bool test() {
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque<int>, std::vector<double>>();
+ test_emplaceable<std::deque<int>, std::vector<Emplaceable>>();
+ }
+
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
test_emplaceable<std::vector<int>, std::vector<Emplaceable>>();
- test_emplaceable<std::deque<int>, std::vector<Emplaceable>>();
test_emplaceable<MinSequenceContainer<int>, MinSequenceContainer<Emplaceable>>();
test_emplaceable<std::vector<int, min_allocator<int>>, std::vector<Emplaceable, min_allocator<Emplaceable>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto emplace_func = [](auto& m, auto key_arg, auto value_arg) {
m.emplace(std::piecewise_construct, std::tuple(key_arg), std::tuple(value_arg));
};
test_emplace_exception_guarantee(emplace_func);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace_hint.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace_hint.pass.cpp
index 588d27e..2367b40 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace_hint.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace_hint.pass.cpp
@@ -44,7 +44,7 @@ static_assert(!CanEmplaceHint<Map, int, double>);
#endif
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -110,7 +110,7 @@ void test() {
assert(r->first == 2);
assert(r->second == 2.0);
assert(std::next(r)->first == 2);
- assert(std::next(r)->second == 2.1);
+ assert(std::next(r)->second == 2.1 || std::next(r)->second == 1.9);
}
{
// hint correct and after duplicates
@@ -183,7 +183,7 @@ void test() {
}
template <class KeyContainer, class ValueContainer>
-void test_emplaceable() {
+constexpr void test_emplaceable() {
using M = std::flat_multimap<int, Emplaceable, std::less<int>, KeyContainer, ValueContainer>;
using R = M::iterator;
@@ -206,23 +206,36 @@ void test_emplaceable() {
assert(r->second == Emplaceable(2, 3.6));
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
test_emplaceable<std::vector<int>, std::vector<Emplaceable>>();
- test_emplaceable<std::deque<int>, std::vector<Emplaceable>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test_emplaceable<std::deque<int>, std::vector<Emplaceable>>();
test_emplaceable<MinSequenceContainer<int>, MinSequenceContainer<Emplaceable>>();
test_emplaceable<std::vector<int, min_allocator<int>>, std::vector<Emplaceable, min_allocator<Emplaceable>>>();
-
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto emplace_func = [](auto& m, auto key_arg, auto value_arg) {
m.emplace_hint(m.begin(), std::piecewise_construct, std::tuple(key_arg), std::tuple(value_arg));
};
test_emplace_exception_guarantee(emplace_func);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter.pass.cpp
index 78040be..6b808b3 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter.pass.cpp
@@ -29,7 +29,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -54,52 +54,64 @@ void test() {
std::same_as<I> decltype(auto) i1 = m.erase(std::next(m.cbegin(), 2));
assert(m.size() == 10);
assert(i1 == std::next(m.begin(), 2));
- assert(std::ranges::equal(
- m,
- std::vector<P>{
- {1, 1.5}, {2, 2.5}, {3, 3.5}, {4, 4.5}, {4, 4.5}, {4, 4.7}, {5, 5.5}, {6, 6.5}, {7, 7.5}, {8, 8.5}}));
+ assert(std::ranges::equal(m.keys(), std::vector<Key>{1, 2, 3, 4, 4, 4, 5, 6, 7, 8}));
+ check_possible_values(m.values(),
+ std::vector<std::vector<Value>>{
+ {1.5}, {2.5, 2.6}, {3.5}, {4.5, 4.7}, {4.5, 4.7}, {4.5, 4.7}, {5.5}, {6.5}, {7.5}, {8.5}});
std::same_as<I> decltype(auto) i2 = m.erase(std::next(m.begin(), 0));
assert(m.size() == 9);
assert(i2 == m.begin());
- assert(std::ranges::equal(
- m, std::vector<P>{{2, 2.5}, {3, 3.5}, {4, 4.5}, {4, 4.5}, {4, 4.7}, {5, 5.5}, {6, 6.5}, {7, 7.5}, {8, 8.5}}));
+ assert(std::ranges::equal(m.keys(), std::vector<Key>{2, 3, 4, 4, 4, 5, 6, 7, 8}));
+ check_possible_values(m.values(),
+ std::vector<std::vector<Value>>{
+ {2.5, 2.6}, {3.5}, {4.5, 4.7}, {4.5, 4.7}, {4.5, 4.7}, {5.5}, {6.5}, {7.5}, {8.5}});
std::same_as<I> decltype(auto) i3 = m.erase(std::next(m.cbegin(), 8));
assert(m.size() == 8);
assert(i3 == m.end());
- assert(std::ranges::equal(
- m, std::vector<P>{{2, 2.5}, {3, 3.5}, {4, 4.5}, {4, 4.5}, {4, 4.7}, {5, 5.5}, {6, 6.5}, {7, 7.5}}));
+ assert(std::ranges::equal(m.keys(), std::vector<Key>{2, 3, 4, 4, 4, 5, 6, 7}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<Value>>{{2.5, 2.6}, {3.5}, {4.5, 4.7}, {4.5, 4.7}, {4.5, 4.7}, {5.5}, {6.5}, {7.5}});
std::same_as<I> decltype(auto) i4 = m.erase(std::next(m.begin(), 1));
assert(m.size() == 7);
assert(i4 == std::next(m.begin()));
- assert(std::ranges::equal(m, std::vector<P>{{2, 2.5}, {4, 4.5}, {4, 4.5}, {4, 4.7}, {5, 5.5}, {6, 6.5}, {7, 7.5}}));
+ assert(std::ranges::equal(m.keys(), std::vector<Key>{2, 4, 4, 4, 5, 6, 7}));
+ check_possible_values(
+ m.values(), std::vector<std::vector<Value>>{{2.5, 2.6}, {4.5, 4.7}, {4.5, 4.7}, {4.5, 4.7}, {5.5}, {6.5}, {7.5}});
std::same_as<I> decltype(auto) i5 = m.erase(std::next(m.cbegin(), 2));
assert(m.size() == 6);
assert(i5 == std::next(m.begin(), 2));
- assert(std::ranges::equal(m, std::vector<P>{{2, 2.5}, {4, 4.5}, {4, 4.7}, {5, 5.5}, {6, 6.5}, {7, 7.5}}));
+ assert(std::ranges::equal(m.keys(), std::vector<Key>{2, 4, 4, 5, 6, 7}));
+ check_possible_values(
+ m.values(), std::vector<std::vector<Value>>{{2.5, 2.6}, {4.5, 4.7}, {4.5, 4.7}, {5.5}, {6.5}, {7.5}});
std::same_as<I> decltype(auto) i6 = m.erase(std::next(m.begin(), 2));
assert(m.size() == 5);
assert(i6 == std::next(m.begin(), 2));
- assert(std::ranges::equal(m, std::vector<P>{{2, 2.5}, {4, 4.5}, {5, 5.5}, {6, 6.5}, {7, 7.5}}));
+ assert(std::ranges::equal(m.keys(), std::vector<Key>{2, 4, 5, 6, 7}));
+ check_possible_values(m.values(), std::vector<std::vector<Value>>{{2.5, 2.6}, {4.5, 4.7}, {5.5}, {6.5}, {7.5}});
std::same_as<I> decltype(auto) i7 = m.erase(std::next(m.cbegin(), 0));
assert(m.size() == 4);
assert(i7 == std::next(m.begin(), 0));
- assert(std::ranges::equal(m, std::vector<P>{{4, 4.5}, {5, 5.5}, {6, 6.5}, {7, 7.5}}));
+ assert(std::ranges::equal(m.keys(), std::vector<Key>{4, 5, 6, 7}));
+ check_possible_values(m.values(), std::vector<std::vector<Value>>{{4.5, 4.7}, {5.5}, {6.5}, {7.5}});
std::same_as<I> decltype(auto) i8 = m.erase(std::next(m.cbegin(), 2));
assert(m.size() == 3);
assert(i8 == std::next(m.begin(), 2));
- assert(std::ranges::equal(m, std::vector<P>{{4, 4.5}, {5, 5.5}, {7, 7.5}}));
+ assert(std::ranges::equal(m.keys(), std::vector<Key>{4, 5, 7}));
+ check_possible_values(m.values(), std::vector<std::vector<Value>>{{4.5, 4.7}, {5.5}, {7.5}});
std::same_as<I> decltype(auto) i9 = m.erase(std::next(m.cbegin(), 2));
assert(m.size() == 2);
assert(i9 == std::next(m.begin(), 2));
- assert(std::ranges::equal(m, std::vector<P>{{4, 4.5}, {5, 5.5}}));
+ assert(std::ranges::equal(m.keys(), std::vector<Key>{4, 5}));
+ check_possible_values(m.values(), std::vector<std::vector<Value>>{{4.5, 4.7}, {5.5}});
std::same_as<I> decltype(auto) i10 = m.erase(m.cbegin());
assert(m.size() == 1);
@@ -112,16 +124,27 @@ void test() {
assert(i11 == m.end());
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); };
test_erase_exception_guarantee(erase_function);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter_iter.pass.cpp
index 103f38c..d7c5bd1df 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter_iter.pass.cpp
@@ -14,6 +14,7 @@
// iterator erase(const_iterator first, const_iterator last);
+#include <algorithm>
#include <compare>
#include <concepts>
#include <deque>
@@ -28,7 +29,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -53,7 +54,8 @@ void test() {
std::same_as<I> decltype(auto) i1 = m.erase(m.cbegin(), m.cbegin());
assert(m.size() == 11);
assert(i1 == m.begin());
- assert(std::ranges::equal(
+ check_invariant(m);
+ assert(std::ranges::is_permutation(
m,
std::vector<P>{
{1, 1.5},
@@ -71,13 +73,17 @@ void test() {
std::same_as<I> decltype(auto) i2 = m.erase(m.cbegin(), std::next(m.cbegin(), 2));
assert(m.size() == 9);
assert(i2 == m.begin());
- assert(std::ranges::equal(
- m, std::vector<P>{{2, 2.6}, {3, 3.5}, {3, 3.6}, {3, 3.7}, {4, 4.5}, {5, 5.5}, {6, 6.5}, {7, 7.5}, {8, 8.5}}));
+ assert(std::ranges::equal(m.keys(), std::vector<Key>{2, 3, 3, 3, 4, 5, 6, 7, 8}));
+ check_possible_values(
+ m.values(),
+ std::vector<std::vector<Value>>{
+ {2.5, 2.6}, {3.5, 3.6, 3.7}, {3.5, 3.6, 3.7}, {3.5, 3.6, 3.7}, {4.5}, {5.5}, {6.5}, {7.5}, {8.5}});
std::same_as<I> decltype(auto) i3 = m.erase(std::next(m.cbegin(), 2), std::next(m.cbegin(), 6));
assert(m.size() == 5);
assert(i3 == std::next(m.begin(), 2));
- assert(std::ranges::equal(m, std::vector<P>{{2, 2.6}, {3, 3.5}, {6, 6.5}, {7, 7.5}, {8, 8.5}}));
+ assert(std::ranges::equal(m.keys(), std::vector<Key>{2, 3, 6, 7, 8}));
+ check_possible_values(m.values(), std::vector<std::vector<Value>>{{2.5, 2.6}, {3.5, 3.6, 3.7}, {6.5}, {7.5}, {8.5}});
std::same_as<I> decltype(auto) i4 = m.erase(m.cbegin(), m.cend());
assert(m.size() == 0);
@@ -85,15 +91,27 @@ void test() {
assert(i4 == m.end());
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); };
test_erase_exception_guarantee(erase_function);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key.pass.cpp
index 7944996fb..d267c55 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key.pass.cpp
@@ -28,7 +28,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer, class Compare = std::less<>>
-void test() {
+constexpr void test() {
using M = std::flat_multimap<int, char, Compare, KeyContainer, ValueContainer>;
auto make = [](std::initializer_list<int> il) {
@@ -78,14 +78,17 @@ void test() {
assert(m.empty());
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<char>>();
test<std::vector<int>, std::vector<char>, std::greater<>>();
- test<std::deque<int>, std::vector<char>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<char>>();
test<MinSequenceContainer<int>, MinSequenceContainer<char>>();
test<std::vector<int, min_allocator<int>>, std::vector<char, min_allocator<char>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto erase_function = [](auto& m, auto key_arg) {
using Map = std::decay_t<decltype(m)>;
using Key = typename Map::key_type;
@@ -94,6 +97,14 @@ int main(int, char**) {
};
test_erase_exception_guarantee(erase_function);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key_transparent.pass.cpp
index 5627a67..ef75e34 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key_transparent.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key_transparent.pass.cpp
@@ -14,6 +14,7 @@
// size_type erase(K&& k);
+#include <algorithm>
#include <compare>
#include <concepts>
#include <deque>
@@ -40,10 +41,10 @@ static_assert(!CanErase<const NonTransparentMap>);
template <class Key, class It>
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&) {
+ constexpr explicit HeterogeneousKey(Key key, It it) : key_(key), it_(it) {}
+ constexpr operator It() && { return it_; }
+ constexpr auto operator<=>(Key key) const { return key_ <=> key; }
+ constexpr friend bool operator<(const HeterogeneousKey&, const HeterogeneousKey&) {
assert(false);
return false;
}
@@ -52,7 +53,7 @@ struct HeterogeneousKey {
};
template <class KeyContainer, class ValueContainer>
-void test_simple() {
+constexpr void test_simple() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::ranges::less, KeyContainer, ValueContainer>;
@@ -73,7 +74,7 @@ void test_simple() {
}
template <class KeyContainer, class ValueContainer>
-void test_transparent_comparator() {
+constexpr void test_transparent_comparator() {
using M = std::flat_multimap<std::string, int, TransparentComparator, KeyContainer, ValueContainer>;
using P = std::pair<std::string, int>;
M m = {
@@ -82,12 +83,14 @@ void test_transparent_comparator() {
auto n = m.erase(Transparent<std::string>{"epsilon"});
assert(n == 2);
- assert(std::ranges::equal(
+ check_invariant(m);
+ assert(std::ranges::is_permutation(
m, std::vector<P>{{"alpha", 1}, {"beta", 2}, {"eta", 4}, {"gamma", 5}, {"gamma", 6}, {"gamma", 7}}));
auto n2 = m.erase(Transparent<std::string>{"aaa"});
assert(n2 == 0);
- assert(std::ranges::equal(
+ check_invariant(m);
+ assert(std::ranges::is_permutation(
m, std::vector<P>{{"alpha", 1}, {"beta", 2}, {"eta", 4}, {"gamma", 5}, {"gamma", 6}, {"gamma", 7}}));
auto n3 = m.erase(Transparent<std::string>{"gamma"});
@@ -115,14 +118,20 @@ void test_transparent_comparator() {
assert(std::ranges::equal(m, std::vector<P>{}));
}
-int main(int, char**) {
+constexpr bool test() {
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test_simple<std::deque<int>, std::vector<double>>();
+ test_transparent_comparator<std::deque<std::string>, std::vector<int>>();
+ }
+
test_simple<std::vector<int>, std::vector<double>>();
- test_simple<std::deque<int>, std::vector<double>>();
test_simple<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test_simple<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
test_transparent_comparator<std::vector<std::string>, std::vector<int>>();
- test_transparent_comparator<std::deque<std::string>, std::vector<int>>();
test_transparent_comparator<MinSequenceContainer<std::string>, MinSequenceContainer<int>>();
test_transparent_comparator<std::vector<std::string, min_allocator<std::string>>,
std::vector<int, min_allocator<int>>>();
@@ -148,7 +157,8 @@ int main(int, char**) {
assert(n == 2);
assert(transparent_used);
}
- {
+
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto erase_transparent = [](auto& m, auto key_arg) {
using Map = std::decay_t<decltype(m)>;
using Key = typename Map::key_type;
@@ -163,6 +173,14 @@ int main(int, char**) {
auto n = m.erase("beta");
assert(n == 2);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/extract.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/extract.pass.cpp
index f5ed4a9..bc1bdcb 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/extract.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/extract.pass.cpp
@@ -35,25 +35,28 @@ static_assert(!CanExtract<std::flat_multimap<int, int> const&>);
static_assert(!CanExtract<std::flat_multimap<int, int> const&&>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using M = std::flat_multimap<int, int, std::less<int>, KeyContainer, ValueContainer>;
M m = M({1, 2, 2, 2, 3, 3}, {4, 5, 6, 7, 8, 9});
std::same_as<typename M::containers> auto containers = std::move(m).extract();
- auto expected_keys = {1, 2, 2, 2, 3, 3};
- auto expected_values = {4, 5, 6, 7, 8, 9};
+ auto expected_keys = {1, 2, 2, 2, 3, 3};
assert(std::ranges::equal(containers.keys, expected_keys));
- assert(std::ranges::equal(containers.values, expected_values));
+ check_possible_values(
+ containers.values, std::vector<std::vector<int>>{{4}, {5, 6, 7}, {5, 6, 7}, {5, 6, 7}, {8, 9}, {8, 9}});
check_invariant(m);
LIBCPP_ASSERT(m.empty());
LIBCPP_ASSERT(m.keys().size() == 0);
LIBCPP_ASSERT(m.values().size() == 0);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<int>>();
- test<std::deque<int>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<int>>();
test<MinSequenceContainer<int>, MinSequenceContainer<int>>();
test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
{
@@ -69,7 +72,7 @@ int main(int, char**) {
LIBCPP_ASSERT(m.values().size() == 0);
}
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
#ifndef TEST_HAS_NO_EXCEPTIONS
using KeyContainer = std::vector<int>;
using ValueContainer = ThrowOnMoveContainer<int>;
@@ -89,5 +92,15 @@ int main(int, char**) {
}
#endif
}
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_cv.pass.cpp
index 88c173d..96f2120 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_cv.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_cv.pass.cpp
@@ -25,7 +25,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -62,13 +62,16 @@ void test() {
assert(r->second == 4.5);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto insert_func = [](auto& m, auto key_arg, auto value_arg) {
using FlatMap = std::decay_t<decltype(m)>;
using value_type = typename FlatMap::value_type;
@@ -77,5 +80,14 @@ int main(int, char**) {
};
test_emplace_exception_guarantee(insert_func);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_initializer_list.pass.cpp
index 098b66c..d11489e 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_initializer_list.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_initializer_list.pass.cpp
@@ -14,6 +14,7 @@
// void insert(initializer_list<value_type> il);
+#include <algorithm>
#include <flat_map>
#include <cassert>
#include <functional>
@@ -25,7 +26,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -61,16 +62,20 @@ void test() {
{4, 1.5},
{4, 2},
};
- assert(std::ranges::equal(m, expected));
+ check_invariant(m);
+ assert(std::ranges::is_permutation(m, expected));
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto insert_func = [](auto& m, const auto& newValues) {
using FlatMap = std::decay_t<decltype(m)>;
using value_type = typename FlatMap::value_type;
@@ -79,5 +84,14 @@ int main(int, char**) {
};
test_insert_range_exception_guarantee(insert_func);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_cv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_cv.pass.cpp
index 9d64504..cde6cd9 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_cv.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_cv.pass.cpp
@@ -25,7 +25,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -76,13 +76,16 @@ void test() {
assert(r->second == 6.5);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto insert_func = [](auto& m, auto key_arg, auto value_arg) {
using FlatMap = std::decay_t<decltype(m)>;
using value_type = typename FlatMap::value_type;
@@ -91,5 +94,14 @@ int main(int, char**) {
};
test_emplace_exception_guarantee(insert_func);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_iter.pass.cpp
index 30cb89d..ad9a769 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_iter.pass.cpp
@@ -40,7 +40,7 @@ static_assert(!CanInsert<Map, int, int>);
static_assert(!CanInsert<Map, cpp20_input_iterator<Pair*>, cpp20_input_iterator<Pair*>>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using P = std::pair<int, double>;
using M = std::flat_multimap<int, double, std::less<int>, KeyContainer, ValueContainer>;
@@ -71,7 +71,8 @@ void test() {
m.insert(cpp17_input_iterator<P*>(ar1), cpp17_input_iterator<P*>(ar1 + sizeof(ar1) / sizeof(ar1[0])));
assert(m.size() == 9);
std::vector<P> expected{{1, 1}, {1, 1.5}, {1, 2}, {2, 1}, {2, 1.5}, {2, 2}, {3, 1}, {3, 1.5}, {3, 2}};
- assert(std::ranges::equal(m, expected));
+ assert(std::ranges::is_permutation(m, expected));
+ check_invariant(m);
m.insert(cpp17_input_iterator<P*>(ar2), cpp17_input_iterator<P*>(ar2 + sizeof(ar2) / sizeof(ar2[0])));
assert(m.size() == 18);
@@ -94,15 +95,20 @@ void test() {
{4, 1},
{4, 1.5},
{4, 2}};
- assert(std::ranges::equal(m, expected2));
+ assert(std::ranges::is_permutation(m, expected2));
+ check_invariant(m);
}
-int main(int, char**) {
+
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); };
test_insert_range_exception_guarantee(insert_func);
}
@@ -112,5 +118,14 @@ int main(int, char**) {
m.insert(v.begin(), v.end());
assert(std::ranges::equal(m, std::vector<std::pair<int, int>>{{1, 1}, {2, 2}, {3, 3}, {4, 4}}));
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_rv.pass.cpp
index 61962f4..d84372a 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_rv.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_rv.pass.cpp
@@ -25,7 +25,7 @@
#include "test_macros.h"
template <class Container, class Pair>
-void do_insert_iter_rv_test() {
+constexpr void do_insert_iter_rv_test() {
using M = Container;
using P = Pair;
using R = typename M::iterator;
@@ -68,7 +68,7 @@ void do_insert_iter_rv_test() {
}
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -79,17 +79,22 @@ void test() {
do_insert_iter_rv_test<M, CP>();
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
test<std::vector<int>, std::vector<MoveOnly>>();
- test<std::deque<int>, std::deque<double>>();
- test<std::deque<int>, std::deque<MoveOnly>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque<int>, std::deque<double>>();
+ test<std::deque<int>, std::deque<MoveOnly>>();
+ }
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<MoveOnly>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
test<std::vector<int, min_allocator<int>>, std::vector<MoveOnly, min_allocator<MoveOnly>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto insert_func = [](auto& m, auto key_arg, auto value_arg) {
using FlatMap = std::decay_t<decltype(m)>;
using value_type = typename FlatMap::value_type;
@@ -98,6 +103,14 @@ int main(int, char**) {
};
test_emplace_exception_guarantee(insert_func);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range.pass.cpp
index 97b8f17..639f1c0 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range.pass.cpp
@@ -41,7 +41,7 @@ static_assert(!CanInsertRange<Map, std::ranges::subrange<int*>>);
static_assert(!CanInsertRange<Map, std::ranges::subrange<double*>>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
@@ -71,9 +71,12 @@ void test() {
}
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<int>>();
- test<std::deque<int>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<int>>();
test<MinSequenceContainer<int>, MinSequenceContainer<int>>();
test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
{
@@ -87,15 +90,24 @@ int main(int, char**) {
{
// The element type of the range doesn't need to be std::pair (P2767).
std::pair<int, int> pa[] = {{3, 3}, {1, 1}, {4, 4}, {1, 1}, {5, 5}};
- std::deque<std::reference_wrapper<std::pair<int, int>>> a(pa, pa + 5);
+ std::vector<std::reference_wrapper<std::pair<int, int>>> a(pa, pa + 5);
std::flat_multimap<int, int> m;
m.insert_range(a);
std::pair<int, int> expected[] = {{1, 1}, {1, 1}, {3, 3}, {4, 4}, {5, 5}};
assert(std::ranges::equal(m, expected));
}
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); };
test_insert_range_exception_guarantee(insert_func);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_rv.pass.cpp
index 5731502..04e6b74 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_rv.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_rv.pass.cpp
@@ -25,7 +25,7 @@
#include "../helpers.h"
template <class Container, class Pair>
-void do_insert_rv_test() {
+constexpr void do_insert_rv_test() {
using M = Container;
using P = Pair;
using R = typename M::iterator;
@@ -56,7 +56,7 @@ void do_insert_rv_test() {
}
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
@@ -68,9 +68,12 @@ void test() {
do_insert_rv_test<M, CP>();
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<MoveOnly>>();
- test<std::deque<int>, std::vector<MoveOnly>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<MoveOnly>>();
test<MinSequenceContainer<int>, MinSequenceContainer<MoveOnly>>();
test<std::vector<int, min_allocator<int>>, std::vector<MoveOnly, min_allocator<MoveOnly>>>();
@@ -102,7 +105,7 @@ int main(int, char**) {
assert(r->first == 3);
assert(r->second == 3);
}
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto insert_func = [](auto& m, auto key_arg, auto value_arg) {
using FlatMap = std::decay_t<decltype(m)>;
using value_type = typename FlatMap::value_type;
@@ -111,6 +114,14 @@ int main(int, char**) {
};
test_emplace_exception_guarantee(insert_func);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_initializer_list.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_initializer_list.pass.cpp
index 334dff0..7f0bb4a 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_initializer_list.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_initializer_list.pass.cpp
@@ -14,6 +14,7 @@
// void insert(sorted_equivalent_t, initializer_list<value_type> il);
+#include <algorithm>
#include <flat_map>
#include <cassert>
#include <functional>
@@ -25,7 +26,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -43,16 +44,20 @@ void test() {
});
assert(m.size() == 12);
V expected[] = {{0, 1}, {1, 1}, {1, 1.5}, {1, 2}, {1, 2}, {1, 3}, {2, 1}, {2, 4}, {3, 1}, {3, 1.5}, {3, 2}, {4, 1}};
- assert(std::ranges::equal(m, expected));
+ assert(std::ranges::is_permutation(m, expected));
+ check_invariant(m);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto insert_func = [](auto& m, const auto& newValues) {
using FlatMap = std::decay_t<decltype(m)>;
using value_type = typename FlatMap::value_type;
@@ -61,6 +66,14 @@ int main(int, char**) {
};
test_insert_range_exception_guarantee(insert_func);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_iter_iter.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_iter_iter.pass.cpp
index 3780847..4dfdefe 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_iter_iter.pass.cpp
@@ -39,7 +39,7 @@ static_assert(!CanInsert<Map, std::sorted_equivalent_t, int, int>);
static_assert(!CanInsert<Map, std::sorted_equivalent_t, cpp20_input_iterator<Pair*>, cpp20_input_iterator<Pair*>>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -77,18 +77,29 @@ void test() {
assert(std::ranges::equal(m, expected2));
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
auto insert_func = [](auto& m, const auto& newValues) {
m.insert(std::sorted_equivalent, newValues.begin(), newValues.end());
};
test_insert_range_exception_guarantee(insert_func);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_transparent.pass.cpp
index 760479a..b33f644 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_transparent.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_transparent.pass.cpp
@@ -43,63 +43,50 @@ static_assert(CanInsert<Map, Iter, std::tuple<short, double>&&>);
static_assert(!CanInsert<Map, int>);
static_assert(!CanInsert<Map, Iter, int>);
-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 <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
- using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
+ using M = std::flat_multimap<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
{
// insert(P&&)
+ bool transparent_used = false;
+ TransparentComparator c(transparent_used);
+ M m(std::sorted_equivalent, {{1, 1}, {2, 2}, {2, 3}, {4, 4}}, c);
+ assert(!transparent_used);
+
+ std::same_as<typename M::iterator> decltype(auto) res = m.insert(std::pair(ConvertibleTransparent<int>{3}, 3));
+
+ assert(res->first == 3);
+ assert(res->second == 3);
// 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, 1}, {2, 2}, {3, 1}, {3, 4}, {4, 4}, {5, 5}};
- expensive_comparisons = 0;
- cheap_comparisons = 0;
- std::same_as<typename M::iterator> decltype(auto) r = m.insert(std::make_pair(3, 3)); // conversion happens first
- assert(expensive_comparisons >= 2);
- assert(cheap_comparisons == 0);
- assert(r == m.begin() + 4);
-
- std::pair<int, int> expected[] = {{1, 1}, {2, 2}, {3, 1}, {3, 4}, {3, 3}, {4, 4}, {5, 5}};
- assert(std::ranges::equal(m, expected));
+ assert(!transparent_used);
}
{
// insert(const_iterator, P&&)
- M m = {{1, 1}, {2, 2}, {3, 1}, {3, 4}, {4, 4}, {5, 5}};
- expensive_comparisons = 0;
- cheap_comparisons = 0;
- std::same_as<typename M::iterator> auto it = m.insert(m.begin(), std::make_pair(3, 3));
- assert(expensive_comparisons >= 2);
- assert(cheap_comparisons == 0);
- assert(it == m.begin() + 2);
- std::pair<int, int> expected[] = {{1, 1}, {2, 2}, {3, 3}, {3, 1}, {3, 4}, {4, 4}, {5, 5}};
- assert(std::ranges::equal(m, expected));
+ bool transparent_used = false;
+ TransparentComparator c(transparent_used);
+ M m(std::sorted_equivalent, {{1, 1}, {2, 2}, {2, 3}, {4, 4}}, c);
+ std::same_as<typename M::iterator> decltype(auto) res =
+ m.insert(m.begin(), std::pair(ConvertibleTransparent<int>{3}, 3));
+ assert(res->first == 3);
+ assert(res->second == 3);
+ // Unlike flat_set, here we can't use key_compare to compare value_type versus P,
+ // so we must eagerly convert to value_type.
+ assert(!transparent_used);
}
}
-int main(int, char**) {
- test<std::vector<CompareCounter>, std::vector<double>>();
- test<std::deque<CompareCounter>, std::vector<double>>();
- test<MinSequenceContainer<CompareCounter>, MinSequenceContainer<double>>();
- test<std::vector<CompareCounter, min_allocator<CompareCounter>>, std::vector<double, min_allocator<double>>>();
+constexpr bool test() {
+ test<std::vector<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
+ test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
+ test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
{
// no ambiguity between insert(pos, P&&) and insert(first, last)
@@ -113,23 +100,26 @@ 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);
}
- {
- auto insert_func = [](auto& m, auto key_arg, auto value_arg) {
- using FlatMap = std::decay_t<decltype(m)>;
- using tuple_type = std::tuple<typename FlatMap::key_type, typename FlatMap::mapped_type>;
- tuple_type t(key_arg, value_arg);
- m.insert(t);
- };
- test_emplace_exception_guarantee(insert_func);
- }
- {
- auto insert_func_iter = [](auto& m, auto key_arg, auto value_arg) {
- using FlatMap = std::decay_t<decltype(m)>;
- using tuple_type = std::tuple<typename FlatMap::key_type, typename FlatMap::mapped_type>;
- tuple_type t(key_arg, value_arg);
- m.insert(m.begin(), t);
- };
- test_emplace_exception_guarantee(insert_func_iter);
+
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ {
+ auto insert_func = [](auto& m, auto key_arg, auto value_arg) {
+ using FlatMap = std::decay_t<decltype(m)>;
+ using tuple_type = std::tuple<typename FlatMap::key_type, typename FlatMap::mapped_type>;
+ tuple_type t(key_arg, value_arg);
+ m.insert(t);
+ };
+ test_emplace_exception_guarantee(insert_func);
+ }
+ {
+ auto insert_func_iter = [](auto& m, auto key_arg, auto value_arg) {
+ using FlatMap = std::decay_t<decltype(m)>;
+ using tuple_type = std::tuple<typename FlatMap::key_type, typename FlatMap::mapped_type>;
+ tuple_type t(key_arg, value_arg);
+ m.insert(m.begin(), t);
+ };
+ test_emplace_exception_guarantee(insert_func_iter);
+ }
}
{
// LWG4239 std::string and C string literal
@@ -140,5 +130,15 @@ int main(int, char**) {
auto it2 = m.insert(m.begin(), {"beta2", 2});
assert(it2 == m.begin() + 4);
}
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/replace.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/replace.pass.cpp
index 86fbaff..5c3211a 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/replace.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/replace.pass.cpp
@@ -35,7 +35,7 @@ static_assert(!CanReplace<Map, std::vector<int>, const std::vector<int>&>);
static_assert(!CanReplace<Map, const std::vector<int>&, const std::vector<int>&>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -51,13 +51,16 @@ void test() {
assert(std::ranges::equal(m.values(), expected_values));
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
#ifndef TEST_HAS_NO_EXCEPTIONS
using KeyContainer = std::vector<int>;
using ValueContainer = ThrowOnMoveContainer<int>;
@@ -78,5 +81,15 @@ int main(int, char**) {
}
#endif
}
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp
index f96155d..efad2d7 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp
@@ -41,7 +41,7 @@ static_assert(NoExceptAdlSwap<
#endif
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -89,11 +89,22 @@ void test() {
}
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp
index ab7be3b..8f31884 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp
@@ -40,7 +40,7 @@ static_assert(NoExceptMemberSwap<
#endif
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -87,11 +87,23 @@ void test() {
}
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<double>>();
- test<std::deque<int>, std::vector<double>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<double>>();
test<MinSequenceContainer<int>, MinSequenceContainer<double>>();
test<std::vector<int, min_allocator<int>>, std::vector<double, min_allocator<double>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp
index 4714013..070fbb0 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp
@@ -23,7 +23,7 @@
#include "test_macros.h"
-int main(int, char**) {
+constexpr bool test() {
{
using M = std::flat_multimap<int, char>;
using Comp = std::less<int>; // the default
@@ -40,7 +40,7 @@ int main(int, char**) {
assert(vc({1, '2'}, {2, '1'}));
assert(!vc({2, '1'}, {1, '2'}));
}
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
using Comp = std::function<bool(int, int)>;
using M = std::flat_multimap<int, int, Comp>;
Comp comp = std::greater<int>();
@@ -74,7 +74,7 @@ int main(int, char**) {
assert(vc({1, 2}, {2, 1}));
assert(!vc({2, 1}, {1, 2}));
}
- {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
using Comp = std::function<bool(const std::vector<int>&, const std::vector<int>&)>;
using M = std::flat_multimap<std::vector<int>, int, Comp>;
Comp comp = [i = 1](const auto& x, const auto& y) { return x[i] < y[i]; };
@@ -94,5 +94,15 @@ int main(int, char**) {
assert(!vc(b, a));
assert(!vc(c, b));
}
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/keys_values.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/keys_values.pass.cpp
index c7c674c..3611cf4 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/keys_values.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/keys_values.pass.cpp
@@ -28,9 +28,10 @@
#include "test_macros.h"
#include "test_allocator.h"
#include "min_allocator.h"
+#include "../helpers.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -43,17 +44,35 @@ void test() {
static_assert(noexcept(m.keys()));
static_assert(noexcept(m.values()));
- auto expected_keys = {2, 2, 3, 4};
- auto expected_values = {'b', 'e', 'c', 'a'};
+ auto expected_keys = {2, 2, 3, 4};
assert(std::ranges::equal(keys, expected_keys));
- assert(std::ranges::equal(values, expected_values));
+ check_possible_values(
+ values,
+ std::vector<std::vector<char>>{
+ {'b', 'e'},
+ {'b', 'e'},
+ {'c'},
+ {'a'},
+ });
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<char>>();
- test<std::deque<int>, std::vector<char>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<char>>();
test<MinSequenceContainer<int>, MinSequenceContainer<char>>();
test<std::vector<int, min_allocator<int>>, std::vector<char, min_allocator<char>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains.pass.cpp
index b3ea0b6..649b5d9 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains.pass.cpp
@@ -25,7 +25,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
{
@@ -62,11 +62,22 @@ void test() {
}
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<int>>();
- test<std::deque<int>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<int>>();
test<MinSequenceContainer<int>, MinSequenceContainer<int>>();
test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains_transparent.pass.cpp
index 42feeb0..69095c2 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains_transparent.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains_transparent.pass.cpp
@@ -37,7 +37,7 @@ static_assert(!CanContains<NonTransparentMap>);
static_assert(!CanContains<const NonTransparentMap>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
@@ -55,9 +55,12 @@ void test() {
assert(m.contains(Transparent<std::string>{"g"}) == false);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<std::string>, std::vector<int>>();
- test<std::deque<std::string>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<std::string>, std::vector<int>>();
test<MinSequenceContainer<std::string>, MinSequenceContainer<int>>();
test<std::vector<std::string, min_allocator<std::string>>, std::vector<int, min_allocator<int>>>();
@@ -77,5 +80,15 @@ int main(int, char**) {
assert(m.contains("beta") == true);
assert(m.contains("charlie") == false);
}
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count.pass.cpp
index 59b8842..277abc3e 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count.pass.cpp
@@ -25,7 +25,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
@@ -61,11 +61,23 @@ void test() {
}
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<int>>();
- test<std::deque<int>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<int>>();
test<MinSequenceContainer<int>, MinSequenceContainer<int>>();
test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count_transparent.pass.cpp
index 6811be5..ee2c9bf 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count_transparent.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count_transparent.pass.cpp
@@ -37,7 +37,7 @@ static_assert(!CanCount<NonTransparentMap>);
static_assert(!CanCount<const NonTransparentMap>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
@@ -63,9 +63,12 @@ void test() {
assert(m.count(Transparent<std::string>{"g"}) == 0);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<std::string>, std::vector<int>>();
- test<std::deque<std::string>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<std::string>, std::vector<int>>();
test<MinSequenceContainer<std::string>, MinSequenceContainer<int>>();
test<std::vector<std::string, min_allocator<std::string>>, std::vector<int, min_allocator<int>>>();
@@ -87,5 +90,14 @@ int main(int, char**) {
assert(m.count("charlie") == 0);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range.pass.cpp
index ac369b7..88932f6 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range.pass.cpp
@@ -26,7 +26,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
{
@@ -71,11 +71,22 @@ void test() {
}
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<char>>();
- test<std::deque<int>, std::vector<char>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<char>>();
test<MinSequenceContainer<int>, MinSequenceContainer<char>>();
test<std::vector<int, min_allocator<int>>, std::vector<char, min_allocator<char>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range_transparent.pass.cpp
index d80c37f..34bc2d8f 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range_transparent.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range_transparent.pass.cpp
@@ -15,6 +15,7 @@
// template<class K> pair<iterator,iterator> equal_range(const K& x);
// template<class K> pair<const_iterator,const_iterator> equal_range(const K& x) const;
+#include <algorithm>
#include <cassert>
#include <deque>
#include <flat_map>
@@ -38,7 +39,7 @@ static_assert(!CanEqualRange<NonTransparentMap>);
static_assert(!CanEqualRange<const NonTransparentMap>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
@@ -62,7 +63,7 @@ void test() {
auto [first, last] = map.equal_range(Transparent<std::string>{expected_key});
auto expected_range =
expected_values | std::views::transform([&](auto&& val) { return std::pair(expected_key, val); });
- assert(std::ranges::equal(std::ranges::subrange(first, last), expected_range));
+ assert(std::ranges::is_permutation(std::ranges::subrange(first, last), expected_range));
};
auto test_not_found = [&](auto&& map, const std::string& expected_key, long expected_offset) {
@@ -90,9 +91,12 @@ void test() {
test_not_found(cm, "zzz", 9);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<std::string>, std::vector<int>>();
- test<std::deque<std::string>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<std::string>, std::vector<int>>();
test<MinSequenceContainer<std::string>, MinSequenceContainer<int>>();
test<std::vector<std::string, min_allocator<std::string>>, std::vector<int, min_allocator<int>>>();
@@ -114,6 +118,14 @@ int main(int, char**) {
assert(first == m.begin() + 1);
assert(last == m.begin() + 3);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find.pass.cpp
index 74b7051..a6e0bd3 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find.pass.cpp
@@ -27,7 +27,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
@@ -47,11 +47,22 @@ void test() {
assert(std::as_const(m).find(9) == m.end());
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<char>>();
- test<std::deque<int>, std::vector<char>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<char>>();
test<MinSequenceContainer<int>, MinSequenceContainer<char>>();
test<std::vector<int, min_allocator<int>>, std::vector<char, min_allocator<char>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find_transparent.pass.cpp
index dff6356..3d2a6b1 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find_transparent.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find_transparent.pass.cpp
@@ -38,7 +38,7 @@ static_assert(!CanFind<NonTransparentMap>);
static_assert(!CanFind<const NonTransparentMap>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
@@ -80,9 +80,12 @@ void test() {
test_find(cm, "zzz", 10);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<std::string>, std::vector<int>>();
- test<std::deque<std::string>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<std::string>, std::vector<int>>();
test<MinSequenceContainer<std::string>, MinSequenceContainer<int>>();
test<std::vector<std::string, min_allocator<std::string>>, std::vector<int, min_allocator<int>>>();
@@ -102,6 +105,14 @@ int main(int, char**) {
auto it = m.find("beta");
assert(it == m.begin() + 1);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound.pass.cpp
index c3befdd..79dd218 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound.pass.cpp
@@ -26,7 +26,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
{
@@ -63,11 +63,22 @@ void test() {
}
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<char>>();
- test<std::deque<int>, std::vector<char>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<char>>();
test<MinSequenceContainer<int>, MinSequenceContainer<char>>();
test<std::vector<int, min_allocator<int>>, std::vector<char, min_allocator<char>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound_transparent.pass.cpp
index 3161ca0..55f836d 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound_transparent.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound_transparent.pass.cpp
@@ -38,7 +38,7 @@ static_assert(!CanLowerBound<NonTransparentMap>);
static_assert(!CanLowerBound<const NonTransparentMap>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
@@ -88,9 +88,12 @@ void test() {
test_lower_bound(cm, "zzz", 11);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<std::string>, std::vector<int>>();
- test<std::deque<std::string>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<std::string>, std::vector<int>>();
test<MinSequenceContainer<std::string>, MinSequenceContainer<int>>();
test<std::vector<std::string, min_allocator<std::string>>, std::vector<int, min_allocator<int>>>();
@@ -110,6 +113,14 @@ int main(int, char**) {
auto it = m.lower_bound("charlie");
assert(it == m.begin() + 3);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound.pass.cpp
index d73d0302..789e5b2 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound.pass.cpp
@@ -26,7 +26,7 @@
#include "min_allocator.h"
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
{
@@ -66,11 +66,22 @@ void test() {
}
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<int>, std::vector<char>>();
- test<std::deque<int>, std::vector<char>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<char>>();
test<MinSequenceContainer<int>, MinSequenceContainer<char>>();
test<std::vector<int, min_allocator<int>>, std::vector<char, min_allocator<char>>>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound_transparent.pass.cpp
index d51d87c..817e8f8 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound_transparent.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound_transparent.pass.cpp
@@ -38,7 +38,7 @@ static_assert(!CanUpperBound<NonTransparentMap>);
static_assert(!CanUpperBound<const NonTransparentMap>);
template <class KeyContainer, class ValueContainer>
-void test() {
+constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;
using M = std::flat_multimap<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
@@ -88,9 +88,12 @@ void test() {
test_upper_bound(cm, "zzz", 11);
}
-int main(int, char**) {
+constexpr bool test() {
test<std::vector<std::string>, std::vector<int>>();
- test<std::deque<std::string>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<std::string>, std::vector<int>>();
test<MinSequenceContainer<std::string>, MinSequenceContainer<int>>();
test<std::vector<std::string, min_allocator<std::string>>, std::vector<int, min_allocator<int>>>();
{
@@ -109,6 +112,14 @@ int main(int, char**) {
auto it = m.upper_bound("charlie");
assert(it == m.begin() + 3);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
return 0;
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.multimap/helpers.h
index 68d7f67..f3edd3b 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/helpers.h
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/helpers.h
@@ -14,18 +14,27 @@
#include <string>
#include <vector>
#include <flat_map>
+#include <ranges>
#include "../flat_helpers.h"
#include "test_allocator.h"
#include "test_macros.h"
template <class... Args>
-void check_invariant(const std::flat_multimap<Args...>& m) {
+constexpr void check_invariant(const std::flat_multimap<Args...>& m) {
assert(m.keys().size() == m.values().size());
const auto& keys = m.keys();
assert(std::is_sorted(keys.begin(), keys.end(), m.key_comp()));
}
+constexpr void check_possible_values(const auto& actual, const auto& expected) {
+ assert(std::ranges::size(actual) == std::ranges::size(expected));
+
+ for (const auto& [actual_value, possible_values] : std::views::zip(actual, expected)) {
+ assert(std::ranges::find(possible_values, actual_value) != std::ranges::end(possible_values));
+ }
+}
+
template <class F>
void test_emplace_exception_guarantee([[maybe_unused]] F&& emplace_function) {
#ifndef TEST_HAS_NO_EXCEPTIONS
diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp
index 86d7769..3031276 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp
@@ -69,6 +69,25 @@ TEST_CONSTEXPR_CXX26 bool test() {
test<std::forward_list<long>>();
test<std::forward_list<double>>();
+ { // Ensure that the result of operator== is converted to bool
+ // See LWG4135.
+ struct Bool {
+ Bool() = default;
+ Bool(const Bool&) = delete;
+ operator bool() const { return true; }
+ };
+
+ struct Int {
+ Bool& operator==(Int) const {
+ static Bool b;
+ return b;
+ }
+ };
+
+ std::forward_list<Int> l;
+ std::erase(l, Int{});
+ }
+
return true;
}
diff --git a/libcxx/test/libcxx/containers/sequences/vector/erase.modules.compile.pass.mm b/libcxx/test/std/containers/sequences/vector/erase.modules.compile.pass.mm
index d270673..d270673 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/erase.modules.compile.pass.mm
+++ b/libcxx/test/std/containers/sequences/vector/erase.modules.compile.pass.mm
diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp
index bac2ea2..6549735 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp
@@ -127,9 +127,9 @@ TEST_CONSTEXPR_CXX20 void emplaceable_concept_tests() {
}
void test_ctor_under_alloc() {
-#if TEST_STD_VER >= 11
int arr1[] = {42};
int arr2[] = {1, 101, 42};
+#if TEST_STD_VER >= 11
{
using C = TCT::vector<>;
using It = forward_iterator<int*>;
@@ -155,6 +155,35 @@ void test_ctor_under_alloc() {
}
}
#endif
+ // FIXME: This is mostly the same test as above, just worse. They should be merged.
+ {
+ typedef std::vector<int, cpp03_allocator<int> > C;
+ typedef C::allocator_type Alloc;
+ {
+ Alloc::construct_called = false;
+ C v(arr1, arr1 + 1);
+ assert(Alloc::construct_called);
+ }
+ {
+ Alloc::construct_called = false;
+ C v(arr2, arr2 + 3);
+ assert(Alloc::construct_called);
+ }
+ }
+ {
+ typedef std::vector<int, cpp03_overload_allocator<int> > C;
+ typedef C::allocator_type Alloc;
+ {
+ Alloc::construct_called = false;
+ C v(arr1, arr1 + 1);
+ assert(Alloc::construct_called);
+ }
+ {
+ Alloc::construct_called = false;
+ C v(arr2, arr2 + 3);
+ assert(Alloc::construct_called);
+ }
+ }
}
// In C++03, you can't instantiate a template with a local type.
diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
index de32504..019f427 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
@@ -141,9 +141,9 @@ TEST_CONSTEXPR_CXX20 void emplaceable_concept_tests() {
}
void test_ctor_under_alloc() {
-#if TEST_STD_VER >= 11
int arr1[] = {42};
int arr2[] = {1, 101, 42};
+#if TEST_STD_VER >= 11
{
using C = TCT::vector<>;
using It = forward_iterator<int*>;
@@ -173,6 +173,37 @@ void test_ctor_under_alloc() {
}
}
#endif
+ // FIXME: This is mostly the same test as above, just worse. They should be merged.
+ {
+ typedef std::vector<int, cpp03_allocator<int> > C;
+ typedef C::allocator_type Alloc;
+ Alloc a;
+ {
+ Alloc::construct_called = false;
+ C v(arr1, arr1 + 1, a);
+ assert(Alloc::construct_called);
+ }
+ {
+ Alloc::construct_called = false;
+ C v(arr2, arr2 + 3, a);
+ assert(Alloc::construct_called);
+ }
+ }
+ {
+ typedef std::vector<int, cpp03_overload_allocator<int> > C;
+ typedef C::allocator_type Alloc;
+ Alloc a;
+ {
+ Alloc::construct_called = false;
+ C v(arr1, arr1 + 1, a);
+ assert(Alloc::construct_called);
+ }
+ {
+ Alloc::construct_called = false;
+ C v(arr2, arr2 + 3, a);
+ assert(Alloc::construct_called);
+ }
+ }
}
TEST_CONSTEXPR_CXX20 bool test() {
diff --git a/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp b/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp
index 6929831..172c97f 100644
--- a/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp
+++ b/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp
@@ -8,10 +8,6 @@
// UNSUPPORTED: c++03, c++11, c++14
-// Older versions of clang may encounter a backend error (see 0295c2ad):
-// Pass-by-value arguments with alignment greater than register width are not supported.
-// XFAIL: target=powerpc{{.*}}-ibm-{{.*}} && clang-18
-
// <experimental/simd>
//
// [simd.class]
diff --git a/libcxx/test/std/experimental/simd/simd.class/simd_unary.pass.cpp b/libcxx/test/std/experimental/simd/simd.class/simd_unary.pass.cpp
index a496938..056d6f6 100644
--- a/libcxx/test/std/experimental/simd/simd.class/simd_unary.pass.cpp
+++ b/libcxx/test/std/experimental/simd/simd.class/simd_unary.pass.cpp
@@ -8,10 +8,6 @@
// UNSUPPORTED: c++03, c++11, c++14
-// Older versions of clang may encounter a backend error (see 0295c2ad):
-// Pass-by-value arguments with alignment greater than register width are not supported.
-// XFAIL: target=powerpc{{.*}}-ibm-{{.*}} && clang-18
-
// FIXME: The following issue occurs on Windows to Armv7 Ubuntu Linux:
// Assertion failed: N->getValueType(0) == MVT::v1i1 && "Expected v1i1 type"
// XFAIL: target=armv7-unknown-linux-gnueabihf
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array.pass.cpp
index 4cd8fad..7bcc584 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array.pass.cpp
@@ -11,7 +11,6 @@
// UNSUPPORTED: c++03, c++11
// These compiler versions and platforms don't enable sized deallocation by default.
-// ADDITIONAL_COMPILE_FLAGS(clang-18): -fsized-deallocation
// ADDITIONAL_COMPILE_FLAGS(apple-clang-16): -fsized-deallocation
// ADDITIONAL_COMPILE_FLAGS(apple-clang-17): -fsized-deallocation
// ADDITIONAL_COMPILE_FLAGS(target=x86_64-w64-windows-gnu): -fsized-deallocation
@@ -20,10 +19,6 @@
// ADDITIONAL_COMPILE_FLAGS(target=armv7-w64-windows-gnu): -fsized-deallocation
// ADDITIONAL_COMPILE_FLAGS(target=arm64ec-w64-windows-gnu): -fsized-deallocation
-// Android clang-r536225 identifies as clang-19.0 but it predates the real
-// LLVM 19.0.0, so it also leaves sized deallocation off by default.
-// UNSUPPORTED: android && clang-19.0
-
// UNSUPPORTED: sanitizer-new-delete
// Sized deallocation was introduced in LLVM 11
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.pass.cpp
index 7b96b01..e6e8532 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete.pass.cpp
@@ -11,7 +11,6 @@
// UNSUPPORTED: c++03, c++11
// These compiler versions and platforms don't enable sized deallocation by default.
-// ADDITIONAL_COMPILE_FLAGS(clang-18): -fsized-deallocation
// ADDITIONAL_COMPILE_FLAGS(apple-clang-16): -fsized-deallocation
// ADDITIONAL_COMPILE_FLAGS(apple-clang-17): -fsized-deallocation
// ADDITIONAL_COMPILE_FLAGS(target=x86_64-w64-windows-gnu): -fsized-deallocation
@@ -20,10 +19,6 @@
// ADDITIONAL_COMPILE_FLAGS(target=armv7-w64-windows-gnu): -fsized-deallocation
// ADDITIONAL_COMPILE_FLAGS(target=arm64ec-w64-windows-gnu): -fsized-deallocation
-// Android clang-r536225 identifies as clang-19.0 but it predates the real
-// LLVM 19.0.0, so it also leaves sized deallocation off by default.
-// UNSUPPORTED: android && clang-19.0
-
// UNSUPPORTED: sanitizer-new-delete
// Sized deallocation was introduced in LLVM 11
diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp
index 3f4317a..678483b 100644
--- a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp
+++ b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp
@@ -15,9 +15,12 @@
#include <concepts>
#include <iterator>
#include <ranges>
+#include <sstream>
#include <type_traits>
#include <utility>
+#include "test_macros.h"
+
// Test for basic properties of C++20 16.3.3.3.6 [customization.point.object].
template <class CPO, class... Args>
constexpr bool test(CPO& o, Args&&...) {
@@ -26,7 +29,7 @@ constexpr bool test(CPO& o, Args&&...) {
static_assert(std::is_trivially_copyable_v<CPO>);
static_assert(std::is_trivially_default_constructible_v<CPO>);
- auto p = o;
+ auto p = o;
using T = decltype(p);
// The type of a customization point object, ignoring cv-qualifiers, shall model semiregular.
@@ -43,7 +46,10 @@ constexpr bool test(CPO& o, Args&&...) {
int a[10];
int arrays[10][10];
-//std::pair<int, int> pairs[10];
+std::pair<int, int> pairs[10];
+#ifndef TEST_HAS_NO_LOCALIZATION
+std::istringstream stream;
+#endif
// [concept.swappable]
static_assert(test(std::ranges::swap, a, a));
@@ -79,21 +85,50 @@ static_assert(test(std::ranges::ssize, a));
// views::empty<T> is not a CPO
static_assert(test(std::views::iota, 1));
static_assert(test(std::views::iota, 1, 10));
-//static_assert(test(std::views::istream<int>, 1);
+#ifndef TEST_HAS_NO_LOCALIZATION
+static_assert(test(std::views::istream<int>, stream));
+#endif
static_assert(test(std::views::single, 4));
+#if TEST_STD_VER >= 23
+static_assert(test(std::views::repeat, 1));
+#endif
+
// [range.adaptors]
static_assert(test(std::views::all, a));
static_assert(test(std::views::common, a));
static_assert(test(std::views::counted, a, 10));
static_assert(test(std::views::drop, a, 10));
-//static_assert(test(std::views::drop_while, a, [](int x){ return x < 10; }));
-//static_assert(test(std::views::elements<0>, pairs));
-static_assert(test(std::views::filter, a, [](int x){ return x < 10; }));
+static_assert(test(std::views::drop_while, a, [](int x) { return x < 10; }));
+static_assert(test(std::views::elements<0>, pairs));
+static_assert(test(std::views::filter, a, [](int x) { return x < 10; }));
static_assert(test(std::views::join, arrays));
-//static_assert(test(std::views::split, a, 4));
+static_assert(test(std::views::keys, pairs));
static_assert(test(std::views::lazy_split, a, 4));
static_assert(test(std::views::reverse, a));
+static_assert(test(std::views::split, a, 4));
static_assert(test(std::views::take, a, 10));
-//static_assert(test(std::views::take_while, a, [](int x){ return x < 10; }));
-static_assert(test(std::views::transform, a, [](int x){ return x + 1; }));
+static_assert(test(std::views::take_while, a, [](int x) { return x < 10; }));
+static_assert(test(std::views::transform, a, [](int x) { return x + 1; }));
+static_assert(test(std::views::values, pairs));
+
+#if TEST_STD_VER >= 23
+// static_assert(test(std::views::adjacent_transform<2>, [](int x, int y) { return x + y; }, a));
+// static_assert(test(std::views::adjacent<2>, a));
+// static_assert(test(std::views::as_const, a));
+static_assert(test(std::views::as_rvalue, a));
+// static_assert(test(std::views::cartesian_product, a, a, a));
+static_assert(test(std::views::chunk_by, a, [](int x, int y) { return x < y; }));
+// static_assert(test(std::views::chunk, a, 1));
+// static_assert(test(std::views::enumerate, a));
+static_assert(test(std::views::join_with, 1));
+// static_assert(test(std::views::stride, a, 1));
+static_assert(test(std::views::zip_transform, [](int x, int y) { return x + y; }, a, a));
+static_assert(test(std::views::zip, a, a));
+#endif
+
+#if TEST_STD_VER >= 26
+// static_assert(test(std::views::cache_latest, a));
+// static_assert(test(std::views::concat, a, a));
+// static_assert(test(std::views::to_input, a));
+#endif
diff --git a/libcxx/test/std/numerics/c.math/signbit.pass.cpp b/libcxx/test/std/numerics/c.math/signbit.pass.cpp
index 2ab4c11b..44ce325 100644
--- a/libcxx/test/std/numerics/c.math/signbit.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/signbit.pass.cpp
@@ -12,7 +12,7 @@
// UNSUPPORTED: windows
// These compilers don't support constexpr `__builtin_signbit` yet.
-// UNSUPPORTED: clang-18, clang-19, apple-clang-16, apple-clang-17
+// UNSUPPORTED: clang-19, apple-clang-16, apple-clang-17
// GCC warns about signbit comparing `bool_v < 0`, which we're testing
// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-bool-compare
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/begin.pass.cpp
new file mode 100644
index 0000000..9b326e1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/begin.pass.cpp
@@ -0,0 +1,127 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr auto begin();
+// constexpr auto begin() const
+// requires range<const InnerView> &&
+// regular_invocable<const F&, range_reference_t<const Views>...>;
+
+#include <ranges>
+
+#include <cassert>
+#include <concepts>
+
+#include "types.h"
+
+template <class T>
+concept HasConstBegin = requires(const T& ct) { ct.begin(); };
+
+template <class T>
+concept HasBegin = requires(T& t) { t.begin(); };
+
+constexpr bool test() {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ {
+ // all underlying iterators should be at the begin position
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, std::views::iota(0), std::ranges::single_view(2.));
+ auto it = v.begin();
+ assert(*it == std::make_tuple(1, 0, 2.0));
+
+ auto const_it = std::as_const(v).begin();
+ assert(*const_it == *it);
+
+ static_assert(!std::same_as<decltype(it), decltype(const_it)>);
+ }
+
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer});
+ auto it = v.begin();
+ assert(*it == std::make_tuple(1));
+ auto cit = std::as_const(v).begin();
+ assert(*cit == std::make_tuple(1));
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, SimpleCommon{buffer}, std::views::iota(0));
+ auto it = v.begin();
+ assert(&*it == &buffer[0]);
+ auto cit = std::as_const(v).begin();
+ assert(&*cit == &buffer[0]);
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(Tie{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::single_view(2.));
+ auto it = v.begin();
+ assert(&std::get<0>(*it) == &buffer[0]);
+ assert(&std::get<1>(*it) == &buffer[0]);
+ assert(std::get<2>(*it) == 2.0);
+ auto cit = std::as_const(v).begin();
+ assert(&std::get<0>(*cit) == &buffer[0]);
+ assert(&std::get<1>(*cit) == &buffer[0]);
+ assert(std::get<2>(*cit) == 2.0);
+ }
+
+ {
+ // single empty range
+ std::ranges::zip_transform_view v(MakeTuple{}, std::ranges::empty_view<int>());
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // empty range at the beginning
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, std::ranges::empty_view<int>(), SimpleCommon{buffer}, SimpleCommon{buffer});
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // empty range in the middle
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, std::ranges::empty_view<int>(), SimpleCommon{buffer});
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // empty range at the end
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::empty_view<int>());
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // underlying const R is not a range
+ using ZTV = std::ranges::zip_transform_view<MakeTuple, SimpleCommon, NoConstBeginView>;
+ static_assert(HasBegin<ZTV>);
+ static_assert(!HasConstBegin<ZTV>);
+ }
+
+ {
+ // Fn cannot be invoked on const range
+ using ZTV = std::ranges::zip_transform_view<NonConstOnlyFn, ConstNonConstDifferentView>;
+ static_assert(HasBegin<ZTV>);
+ static_assert(!HasConstBegin<ZTV>);
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/cpo.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/cpo.pass.cpp
new file mode 100644
index 0000000..4a0bf7b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/cpo.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::views::zip_transform
+
+#include <ranges>
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <functional>
+#include <type_traits>
+#include <vector>
+
+#include "types.h"
+
+struct NotMoveConstructible {
+ NotMoveConstructible() = default;
+ NotMoveConstructible(NotMoveConstructible&&) = delete;
+ int operator()() const { return 5; }
+};
+
+struct NotCopyConstructible {
+ NotCopyConstructible() = default;
+ NotCopyConstructible(NotCopyConstructible&&) = default;
+ NotCopyConstructible(const NotCopyConstructible&) = delete;
+ int operator()() const { return 5; }
+};
+
+struct NotInvocable {};
+
+template <class... Args>
+struct Invocable {
+ int operator()(Args...) const { return 5; }
+};
+
+struct ReturnNotObject {
+ void operator()() const {}
+};
+
+// LWG3773 views::zip_transform still requires F to be copy_constructible when empty pack
+static_assert(std::is_invocable_v<decltype((std::views::zip_transform)), NotCopyConstructible>);
+
+static_assert(!std::is_invocable_v<decltype((std::views::zip_transform))>);
+static_assert(!std::is_invocable_v<decltype((std::views::zip_transform)), NotMoveConstructible>);
+static_assert(!std::is_invocable_v<decltype((std::views::zip_transform)), NotInvocable>);
+static_assert(std::is_invocable_v<decltype((std::views::zip_transform)), Invocable<>>);
+static_assert(!std::is_invocable_v<decltype((std::views::zip_transform)), ReturnNotObject>);
+
+static_assert(std::is_invocable_v<decltype((std::views::zip_transform)), //
+ Invocable<int>, //
+ std::ranges::iota_view<int, int>>);
+static_assert(!std::is_invocable_v<decltype((std::views::zip_transform)), //
+ Invocable<>, //
+ std::ranges::iota_view<int, int>>);
+static_assert(!std::is_invocable_v<decltype((std::views::zip_transform)),
+ Invocable<int>,
+ std::ranges::iota_view<int, int>,
+ std::ranges::iota_view<int, int>>);
+static_assert(std::is_invocable_v<decltype((std::views::zip_transform)),
+ Invocable<int, int>,
+ std::ranges::iota_view<int, int>,
+ std::ranges::iota_view<int, int>>);
+
+constexpr bool test() {
+ {
+ // zip_transform function with no ranges
+ auto v = std::views::zip_transform(Invocable<>{});
+ assert(std::ranges::empty(v));
+ static_assert(std::is_same_v<decltype(v), std::ranges::empty_view<int>>);
+ }
+
+ {
+ // zip_transform views
+ int buffer1[] = {1, 2, 3, 4, 5, 6, 7, 8};
+ int buffer2[] = {9, 10, 11, 12};
+ auto view1 = std::views::all(buffer1);
+ auto view2 = std::views::all(buffer2);
+ std::same_as<std::ranges::zip_transform_view<std::plus<>, decltype(view1), decltype(view2)>> decltype(auto) v =
+ std::views::zip_transform(std::plus{}, buffer1, buffer2);
+ assert(std::ranges::size(v) == 4);
+ auto expected = {10, 12, 14, 16};
+ assert(std::ranges::equal(v, expected));
+ static_assert(std::is_same_v<std::ranges::range_reference_t<decltype(v)>, int>);
+ }
+
+ {
+ // zip_transform a viewable range
+ std::array a{1, 2, 3};
+ auto id = [](auto& x) -> decltype(auto) { return (x); };
+ std::same_as<
+ std::ranges::zip_transform_view<decltype(id), std::ranges::ref_view<std::array<int, 3>>>> decltype(auto) v =
+ std::views::zip_transform(id, a);
+ assert(&v[0] == &a[0]);
+ static_assert(std::is_same_v<std::ranges::range_reference_t<decltype(v)>, int&>);
+ }
+
+ int buffer[] = {1, 2, 3};
+ {
+ // one range
+ auto v = std::views::zip_transform(MakeTuple{}, SimpleCommon{buffer});
+ assert(std::ranges::equal(v, std::vector{std::tuple(1), std::tuple(2), std::tuple(3)}));
+ }
+
+ {
+ // two ranges
+ auto v = std::views::zip_transform(GetFirst{}, SimpleCommon{buffer}, std::views::iota(0));
+ assert(std::ranges::equal(v, std::vector{1, 2, 3}));
+ }
+
+ {
+ // three ranges
+ auto v = std::views::zip_transform(Tie{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::single_view(2.));
+ assert(std::ranges::equal(v, std::vector{std::tuple(1, 1, 2.0)}));
+ }
+
+ {
+ // single empty range
+ auto v = std::views::zip_transform(MakeTuple{}, std::ranges::empty_view<int>());
+ assert(std::ranges::empty(v));
+ }
+
+ {
+ // empty range at the beginning
+ auto v = std::views::zip_transform(
+ MakeTuple{}, std::ranges::empty_view<int>(), SimpleCommon{buffer}, SimpleCommon{buffer});
+ assert(std::ranges::empty(v));
+ }
+
+ {
+ // empty range in the middle
+ auto v = std::views::zip_transform(
+ MakeTuple{}, SimpleCommon{buffer}, std::ranges::empty_view<int>(), SimpleCommon{buffer});
+ assert(std::ranges::empty(v));
+ }
+
+ {
+ // empty range at the end
+ auto v = std::views::zip_transform(
+ MakeTuple{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::empty_view<int>());
+ assert(std::ranges::empty(v));
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctad.compile.pass.cpp
new file mode 100644
index 0000000..9254dd1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctad.compile.pass.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.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<class F, class... Rs>
+// zip_transform_view(F, Rs&&...) -> zip_transform_view<F, views::all_t<Rs>...>;
+
+#include <cassert>
+#include <ranges>
+
+#include "types.h"
+
+struct Container {
+ int* begin() const;
+ int* end() const;
+};
+
+struct Fn {
+ int operator()(auto&&...) const { return 5; }
+};
+
+void testCTAD() {
+ static_assert(std::is_same_v<decltype(std::ranges::zip_transform_view(Fn{}, Container{})),
+ std::ranges::zip_transform_view<Fn, std::ranges::owning_view<Container>>>);
+
+ static_assert(std::is_same_v<decltype(std::ranges::zip_transform_view(Fn{}, Container{}, IntView{})),
+ std::ranges::zip_transform_view<Fn, std::ranges::owning_view<Container>, IntView>>);
+
+ Container c{};
+ static_assert(
+ std::is_same_v<
+ decltype(std::ranges::zip_transform_view(Fn{}, Container{}, IntView{}, c)),
+ std::ranges::
+ zip_transform_view<Fn, std::ranges::owning_view<Container>, IntView, std::ranges::ref_view<Container>>>);
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctor.default.pass.cpp
new file mode 100644
index 0000000..751210f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctor.default.pass.cpp
@@ -0,0 +1,147 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// zip_transform_view() = default;
+
+#include <ranges>
+
+#include <cassert>
+#include <type_traits>
+
+#include "types.h"
+
+constexpr int buff[] = {1, 2, 3};
+
+struct DefaultConstructibleView : std::ranges::view_base {
+ constexpr DefaultConstructibleView() : begin_(buff), end_(buff + 3) {}
+ constexpr int const* begin() const { return begin_; }
+ constexpr int const* end() const { return end_; }
+
+private:
+ int const* begin_;
+ int const* end_;
+};
+
+struct NonDefaultConstructibleView : std::ranges::view_base {
+ NonDefaultConstructibleView() = delete;
+ int* begin() const;
+ int* end() const;
+};
+
+struct DefaultConstructibleFn {
+ constexpr int operator()(const auto&... x) const { return (x + ...); }
+};
+
+struct NonDefaultConstructibleFn {
+ NonDefaultConstructibleFn() = delete;
+ constexpr int operator()(const auto&... x) const;
+};
+
+// The default constructor requires all underlying views to be default constructible.
+// It is implicitly required by the zip_view's constructor.
+static_assert(std::is_default_constructible_v<std::ranges::zip_transform_view< //
+ DefaultConstructibleFn, //
+ DefaultConstructibleView>>);
+static_assert(std::is_default_constructible_v<std::ranges::zip_transform_view< //
+ DefaultConstructibleFn, //
+ DefaultConstructibleView,
+ DefaultConstructibleView>>);
+static_assert(!std::is_default_constructible_v<std::ranges::zip_transform_view< //
+ NonDefaultConstructibleFn, //
+ DefaultConstructibleView>>);
+static_assert(!std::is_default_constructible_v<std::ranges::zip_transform_view< //
+ DefaultConstructibleFn, //
+ NonDefaultConstructibleView>>);
+static_assert(!std::is_default_constructible_v<std::ranges::zip_transform_view< //
+ DefaultConstructibleFn, //
+ DefaultConstructibleView,
+ NonDefaultConstructibleView>>);
+
+constexpr bool test() {
+ {
+ using View =
+ std::ranges::zip_transform_view<DefaultConstructibleFn, DefaultConstructibleView, DefaultConstructibleView>;
+ View v = View(); // the default constructor is not explicit
+ assert(v.size() == 3);
+ auto it = v.begin();
+ assert(*it++ == 2);
+ assert(*it++ == 4);
+ assert(*it == 6);
+ }
+
+ {
+ // one range
+ using View = std::ranges::zip_transform_view<MakeTuple, DefaultConstructibleView>;
+ View v = View(); // the default constructor is not explicit
+ auto it = v.begin();
+ assert(*it == std::make_tuple(1));
+ }
+
+ {
+ // two ranges
+ using View = std::ranges::zip_transform_view<MakeTuple, DefaultConstructibleView, std::ranges::iota_view<int>>;
+ View v = View(); // the default constructor is not explicit
+ auto it = v.begin();
+ assert(*it == std::tuple(1, 0));
+ }
+
+ {
+ // three ranges
+ using View = std::ranges::
+ zip_transform_view<MakeTuple, DefaultConstructibleView, DefaultConstructibleView, std::ranges::iota_view<int>>;
+ View v = View(); // the default constructor is not explicit
+ auto it = v.begin();
+ assert(*it == std::tuple(1, 1, 0));
+ }
+
+ {
+ // single empty range
+ std::ranges::zip_transform_view v(MakeTuple{}, std::ranges::empty_view<int>());
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // empty range at the beginning
+ using View = std::ranges::
+ zip_transform_view<MakeTuple, std::ranges::empty_view<int>, DefaultConstructibleView, DefaultConstructibleView>;
+ View v = View(); // the default constructor is not explicit
+ assert(v.empty());
+ }
+
+ {
+ // empty range in the middle
+ using View =
+ std::ranges::zip_transform_view<MakeTuple,
+ DefaultConstructibleView,
+ std::ranges::empty_view<int>,
+ DefaultConstructibleView,
+ DefaultConstructibleView>;
+ View v = View(); // the default constructor is not explicit
+ assert(v.empty());
+ }
+
+ {
+ // empty range at the end
+ using View = std::ranges::
+ zip_transform_view<MakeTuple, DefaultConstructibleView, DefaultConstructibleView, std::ranges::empty_view<int>>;
+ View v = View(); // the default constructor is not explicit
+ assert(v.empty());
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctor.views.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctor.views.pass.cpp
new file mode 100644
index 0000000..5f3b5a3
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/ctor.views.pass.cpp
@@ -0,0 +1,144 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr explicit zip_transform_view(F, Views...)
+
+#include <algorithm>
+#include <ranges>
+#include <vector>
+
+#include "types.h"
+
+struct Fn {
+ int operator()(auto&&...) const { return 5; }
+};
+
+template <class T, class... Args>
+concept IsImplicitlyConstructible = requires(T val, Args... args) { val = {std::forward<Args>(args)...}; };
+
+// test constructor is explicit
+static_assert(std::constructible_from<std::ranges::zip_transform_view<Fn, IntView>, Fn, IntView>);
+static_assert(!IsImplicitlyConstructible<std::ranges::zip_transform_view<Fn, IntView>, Fn, IntView>);
+
+static_assert(std::constructible_from<std::ranges::zip_transform_view<Fn, IntView, IntView>, Fn, IntView, IntView>);
+static_assert(!IsImplicitlyConstructible<std::ranges::zip_transform_view<Fn, IntView, IntView>, Fn, IntView, IntView>);
+
+struct MoveAwareView : std::ranges::view_base {
+ int moves = 0;
+ constexpr MoveAwareView() = default;
+ constexpr MoveAwareView(MoveAwareView&& other) : moves(other.moves + 1) { other.moves = 1; }
+ constexpr MoveAwareView& operator=(MoveAwareView&& other) {
+ moves = other.moves + 1;
+ other.moves = 0;
+ return *this;
+ }
+ constexpr const int* begin() const { return &moves; }
+ constexpr const int* end() const { return &moves + 1; }
+};
+
+template <class View1, class View2>
+constexpr void constructorTest(auto&& buffer1, auto&& buffer2) {
+ std::ranges::zip_transform_view v{MakeTuple{}, View1{buffer1}, View2{buffer2}};
+ auto [i, j] = *v.begin();
+ assert(i == buffer1[0]);
+ assert(j == buffer2[0]);
+};
+
+constexpr bool test() {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ int buffer2[4] = {9, 8, 7, 6};
+
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer2});
+ assert(std::ranges::equal(v, std::vector{std::tuple(9), std::tuple(8), std::tuple(7), std::tuple(6)}));
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, SimpleCommon{buffer}, std::views::iota(0));
+ assert(std::ranges::equal(v, std::vector{1, 2, 3, 4, 5, 6, 7, 8}));
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(Tie{}, SimpleCommon{buffer}, SimpleCommon{buffer2}, std::ranges::single_view(2.));
+ assert(std::ranges::equal(v, std::vector{std::tuple(1, 9, 2.0)}));
+ }
+
+ {
+ // single empty range
+ std::ranges::zip_transform_view v(MakeTuple{}, std::ranges::empty_view<int>());
+ assert(std::ranges::empty(v));
+ }
+
+ {
+ // empty range at the beginning
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, std::ranges::empty_view<int>(), SimpleCommon{buffer}, SimpleCommon{buffer});
+ assert(std::ranges::empty(v));
+ }
+
+ {
+ // empty range in the middle
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, std::ranges::empty_view<int>(), SimpleCommon{buffer});
+ assert(std::ranges::empty(v));
+ }
+
+ {
+ // empty range at the end
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::empty_view<int>());
+ assert(std::ranges::empty(v));
+ }
+ {
+ // constructor from views
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.));
+ auto [i, j, k] = *v.begin();
+ assert(i == 1);
+ assert(j == 0);
+ assert(k == 2.0);
+ }
+
+ {
+ // arguments are moved once
+ MoveAwareView mv;
+ std::ranges::zip_transform_view v{MakeTuple{}, std::move(mv), MoveAwareView{}};
+ auto [numMoves1, numMoves2] = *v.begin();
+ assert(numMoves1 == 3); // one move from the local variable to parameter, one move from parameter to member
+ assert(numMoves2 == 2);
+ }
+
+ // input and forward
+ {
+ constructorTest<InputCommonView, ForwardSizedView>(buffer, buffer2);
+ }
+
+ // bidi and random_access
+ {
+ constructorTest<BidiCommonView, SizedRandomAccessView>(buffer, buffer2);
+ }
+
+ // contiguous
+ {
+ constructorTest<ContiguousCommonView, ContiguousCommonView>(buffer, buffer2);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/end.pass.cpp
new file mode 100644
index 0000000..e6c7094
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/end.pass.cpp
@@ -0,0 +1,147 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr auto end()
+// constexpr auto end() const
+// requires range<const InnerView> &&
+// regular_invocable<const F&, range_reference_t<const Views>...>;
+
+#include <ranges>
+
+#include "types.h"
+
+template <class T>
+concept HasConstEnd = requires(const T& ct) { ct.end(); };
+
+template <class T>
+concept HasEnd = requires(T& t) { t.end(); };
+
+constexpr bool test() {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ {
+ // simple test
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, std::views::iota(0), std::ranges::single_view(2.));
+ assert(v.begin() != v.end());
+ assert(std::as_const(v).begin() != std::as_const(v).end());
+ assert(v.begin() + 1 == v.end());
+ assert(std::as_const(v).begin() + 1 == std::as_const(v).end());
+ }
+
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer});
+ auto it = v.begin();
+ assert(it + 8 == v.end());
+ assert(it + 8 == std::as_const(v).end());
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, SimpleCommon{buffer}, std::views::iota(0));
+ auto it = v.begin();
+ assert(it + 8 == v.end());
+ assert(it + 8 == std::as_const(v).end());
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(Tie{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::single_view(2.));
+ auto it = v.begin();
+ assert(it + 1 == v.end());
+ assert(it + 1 == std::as_const(v).end());
+ }
+
+ {
+ // single empty range
+ std::ranges::zip_transform_view v(MakeTuple{}, std::ranges::empty_view<int>());
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // empty range at the beginning
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, std::ranges::empty_view<int>(), SimpleCommon{buffer}, SimpleCommon{buffer});
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // empty range in the middle
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, std::ranges::empty_view<int>(), SimpleCommon{buffer});
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // empty range at the end
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::empty_view<int>());
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // common_range<InnerView>
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer});
+ auto it = v.begin();
+ auto const_it = std::as_const(v).begin();
+ auto st = v.end();
+ auto const_st = std::as_const(v).end();
+
+ static_assert(!std::same_as<decltype(it), decltype(const_it)>);
+ static_assert(!std::same_as<decltype(st), decltype(const_st)>);
+ static_assert(std::same_as<decltype(it), decltype(st)>);
+ static_assert(std::same_as<decltype(const_it), decltype(const_st)>);
+
+ assert(it + 8 == st);
+ assert(const_it + 8 == const_st);
+ }
+ {
+ // !common_range<InnerView>
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleNonCommon{buffer});
+ auto it = v.begin();
+ auto const_it = std::as_const(v).begin();
+ auto st = v.end();
+ auto const_st = std::as_const(v).end();
+
+ static_assert(!std::same_as<decltype(it), decltype(const_it)>);
+ static_assert(!std::same_as<decltype(st), decltype(const_st)>);
+ static_assert(!std::same_as<decltype(it), decltype(st)>);
+ static_assert(!std::same_as<decltype(const_it), decltype(const_st)>);
+
+ assert(it + 8 == st);
+ assert(const_it + 8 == const_st);
+ }
+
+ {
+ // underlying const R is not a range
+ using ZTV = std::ranges::zip_transform_view<MakeTuple, SimpleCommon, NoConstBeginView>;
+ static_assert(HasEnd<ZTV>);
+ static_assert(!HasConstEnd<ZTV>);
+ }
+
+ {
+ // Fn cannot invoke on const range
+ using ZTV = std::ranges::zip_transform_view<NonConstOnlyFn, ConstNonConstDifferentView>;
+ static_assert(HasEnd<ZTV>);
+ static_assert(!HasConstEnd<ZTV>);
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/general.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/general.pass.cpp
new file mode 100644
index 0000000..3c35de2
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/general.pass.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// Some basic examples of how zip_tranform_view might be used in the wild. This is a general
+// collection of sample algorithms and functions that try to mock general usage of
+// this view.
+
+#include <ranges>
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <vector>
+
+int main(int, char**) {
+ std::vector v1 = {1, 2};
+ std::vector v2 = {4, 5, 6};
+ auto ztv = std::views::zip_transform(std::plus(), v1, v2);
+ auto expected = {5, 7};
+ assert(std::ranges::equal(ztv, expected));
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/arithmetic.pass.cpp
new file mode 100644
index 0000000..d697ae5
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/arithmetic.pass.cpp
@@ -0,0 +1,237 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr iterator& operator+=(difference_type x) requires random_access_range<Base>;
+// constexpr iterator& operator-=(difference_type x) requires random_access_range<Base>;
+// friend constexpr iterator operator+(const iterator& i, difference_type n)
+// requires random_access_range<Base>;
+// friend constexpr iterator operator+(difference_type n, const iterator& i)
+// requires random_access_range<Base>;
+// friend constexpr iterator operator-(const iterator& i, difference_type n)
+// requires random_access_range<Base>;
+// friend constexpr difference_type operator-(const iterator& x, const iterator& y)
+// requires sized_sentinel_for<ziperator<Const>, ziperator<Const>>;
+
+#include <ranges>
+
+#include <array>
+#include <concepts>
+#include <functional>
+
+#include "../types.h"
+
+template <class T, class U>
+concept canPlusEqual = requires(T& t, U& u) { t += u; };
+
+template <class T, class U>
+concept canPlus = requires(T& t, U& u) { t + u; };
+
+template <class T, class U>
+concept canMinusEqual = requires(T& t, U& u) { t -= u; };
+
+template <class T, class U>
+concept canMinus = requires(T& t, U& u) { t - u; };
+
+constexpr bool test() {
+ int buffer1[5] = {1, 2, 3, 4, 5};
+ SizedRandomAccessView a{buffer1};
+ static_assert(std::ranges::random_access_range<decltype(a)>);
+
+ std::array b{4.1, 3.2, 4.3, 0.1, 0.2};
+ static_assert(std::ranges::contiguous_range<decltype(b)>);
+
+ {
+ // operator+(x, n) and operator+=
+ std::ranges::zip_transform_view v(MakeTuple{}, a, b);
+ auto it1 = v.begin();
+ using Iter = decltype(it1);
+
+ std::same_as<Iter> decltype(auto) it2 = it1 + 3;
+ assert(*it2 == std::tuple(4, 0.1));
+
+ std::same_as<Iter> decltype(auto) it3 = 3 + it1;
+ assert(*it3 == std::tuple(4, 0.1));
+
+ std::same_as<Iter&> decltype(auto) it1_ref = it1 += 3;
+ assert(&it1_ref == &it1);
+ assert(*it1_ref == std::tuple(4, 0.1));
+ assert(*it1 == std::tuple(4, 0.1));
+
+ static_assert(canPlus<Iter, std::intptr_t>);
+ static_assert(canPlusEqual<Iter, std::intptr_t>);
+ }
+
+ {
+ // operator-(x, n) and operator-=
+ std::ranges::zip_transform_view v(MakeTuple{}, a, b);
+ auto it1 = v.end();
+ using Iter = decltype(it1);
+
+ std::same_as<Iter> decltype(auto) it2 = it1 - 3;
+ assert(*it2 == std::tuple(3, 4.3));
+
+ std::same_as<Iter&> decltype(auto) it1_ref = it1 -= 3;
+ assert(&it1_ref == &it1);
+ assert(*it1_ref == std::tuple(3, 4.3));
+ assert(*it1 == std::tuple(3, 4.3));
+
+ static_assert(canMinusEqual<Iter, std::intptr_t>);
+ static_assert(canMinus<Iter, std::intptr_t>);
+ }
+
+ {
+ // operator-(x, y)
+ std::ranges::zip_transform_view v(MakeTuple{}, a, b);
+ assert((v.end() - v.begin()) == 5);
+
+ auto it1 = v.begin() + 2;
+ auto it2 = v.end() - 1;
+
+ using Iter = decltype(it1);
+
+ std::same_as<std::iter_difference_t<Iter>> decltype(auto) n = it1 - it2;
+ assert(n == -2);
+ }
+
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer1});
+ auto it = v.begin();
+ assert(*it == std::make_tuple(1));
+
+ it += 4;
+ assert(*it == std::make_tuple(5));
+
+ it -= 1;
+ assert(*it == std::make_tuple(4));
+
+ auto it2 = it - 2;
+ assert(*it2 == std::make_tuple(2));
+
+ auto it3 = 3 + it2;
+ assert(*it3 == std::make_tuple(5));
+
+ assert(it3 - it2 == 3);
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer1}, std::views::iota(0));
+ auto it = v.begin();
+ assert(*it == std::make_tuple(1, 0));
+
+ it += 4;
+ assert(*it == std::make_tuple(5, 4));
+
+ it -= 1;
+ assert(*it == std::make_tuple(4, 3));
+
+ auto it2 = it - 2;
+ assert(*it2 == std::make_tuple(2, 1));
+
+ auto it3 = 3 + it2;
+ assert(*it3 == std::make_tuple(5, 4));
+
+ assert(it3 - it2 == 3);
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(
+ Tie{}, SimpleCommon{buffer1}, SimpleCommon{buffer1}, std::ranges::single_view(2.));
+ auto it = v.begin();
+ assert(*it == std::make_tuple(1, 1, 2.0));
+
+ it += 1;
+ assert(it == v.end());
+
+ it -= 1;
+ assert(it == v.begin());
+
+ auto it2 = it + 1;
+ assert(it2 == v.end());
+
+ auto it3 = it2 - 1;
+ assert(it3 == v.begin());
+
+ assert(it3 - it2 == -1);
+ }
+
+ {
+ // single empty range
+ std::ranges::zip_transform_view v(MakeTuple{}, std::ranges::empty_view<int>());
+ auto it = v.begin();
+ auto it2 = v.end();
+ assert(it2 - it == 0);
+ }
+
+ {
+ // empty range at the beginning
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, std::ranges::empty_view<int>(), SimpleCommon{buffer1}, SimpleCommon{buffer1});
+ auto it = v.begin();
+ auto it2 = v.end();
+ assert(it2 - it == 0);
+ }
+
+ {
+ // empty range in the middle
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer1}, std::ranges::empty_view<int>(), SimpleCommon{buffer1});
+ auto it = v.begin();
+ auto it2 = v.end();
+ assert(it2 - it == 0);
+ }
+
+ {
+ // empty range at the end
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer1}, SimpleCommon{buffer1}, std::ranges::empty_view<int>());
+ auto it = v.begin();
+ auto it2 = v.end();
+ assert(it2 - it == 0);
+ }
+ {
+ // One of the ranges is not random access
+ std::ranges::zip_transform_view v(MakeTuple{}, a, b, ForwardSizedView{buffer1});
+ auto it1 = v.begin();
+ using Iter = decltype(it1);
+ static_assert(!canPlus<Iter, std::intptr_t>);
+ static_assert(!canPlus<std::intptr_t, Iter>);
+ static_assert(!canPlusEqual<Iter, std::intptr_t>);
+ static_assert(!canMinus<Iter, std::intptr_t>);
+ static_assert(canMinus<Iter, Iter>);
+ static_assert(!canMinusEqual<Iter, std::intptr_t>);
+
+ auto it2 = ++v.begin();
+ assert((it2 - it1) == 1);
+ }
+
+ {
+ // One of the ranges does not have sized sentinel
+ std::ranges::zip_transform_view v(MakeTuple{}, a, b, InputCommonView{buffer1});
+ using Iter = decltype(v.begin());
+ static_assert(!canPlus<Iter, std::intptr_t>);
+ static_assert(!canPlus<std::intptr_t, Iter>);
+ static_assert(!canPlusEqual<Iter, std::intptr_t>);
+ static_assert(!canMinus<Iter, std::intptr_t>);
+ static_assert(!canMinus<Iter, Iter>);
+ static_assert(!canMinusEqual<Iter, std::intptr_t>);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/compare.pass.cpp
new file mode 100644
index 0000000..2befb7e
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/compare.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// friend constexpr bool operator==(const iterator& x, const iterator& y)
+// requires equality_comparable<ziperator<Const>>;
+
+// friend constexpr auto operator<=>(const iterator& x, const iterator& y)
+// requires random_access_range<Base>;
+
+#include <ranges>
+
+#include <compare>
+
+#include "test_iterators.h"
+#include "../types.h"
+
+constexpr void compareOperatorTest(auto&& iter1, auto&& iter2) {
+ assert(!(iter1 < iter1));
+ assert(iter1 < iter2);
+ assert(!(iter2 < iter1));
+ assert(iter1 <= iter1);
+ assert(iter1 <= iter2);
+ assert(!(iter2 <= iter1));
+ assert(!(iter1 > iter1));
+ assert(!(iter1 > iter2));
+ assert(iter2 > iter1);
+ assert(iter1 >= iter1);
+ assert(!(iter1 >= iter2));
+ assert(iter2 >= iter1);
+ assert(iter1 == iter1);
+ assert(!(iter1 == iter2));
+ assert(iter2 == iter2);
+ assert(!(iter1 != iter1));
+ assert(iter1 != iter2);
+ assert(!(iter2 != iter2));
+}
+
+constexpr void spaceshipTest(auto&& iter1, auto&& iter2) {
+ using Iter = decltype(iter1);
+ static_assert(std::three_way_comparable<Iter>);
+ assert((iter1 <=> iter2) == std::strong_ordering::less);
+ assert((iter1 <=> iter1) == std::strong_ordering::equal);
+ assert((iter2 <=> iter2) == std::strong_ordering::equal);
+ assert((iter2 <=> iter1) == std::strong_ordering::greater);
+}
+
+constexpr void inequalityOperatorsDoNotExistTest(auto&& iter1, auto&& iter2) {
+ using Iter1 = decltype(iter1);
+ using Iter2 = decltype(iter2);
+ static_assert(!std::is_invocable_v<std::less<>, Iter1, Iter2>);
+ static_assert(!std::is_invocable_v<std::less_equal<>, Iter1, Iter2>);
+ static_assert(!std::is_invocable_v<std::greater<>, Iter1, Iter2>);
+ static_assert(!std::is_invocable_v<std::greater_equal<>, Iter1, Iter2>);
+}
+
+constexpr bool test() {
+ {
+ // Test a new-school iterator with operator<=>; the iterator should also have operator<=>.
+ using It = three_way_contiguous_iterator<int*>;
+ using SubRange = std::ranges::subrange<It>;
+ static_assert(std::three_way_comparable<It>);
+
+ int a[] = {1, 2, 3, 4};
+ int b[] = {5, 6, 7, 8, 9};
+ auto r = std::views::zip_transform(MakeTuple{}, SubRange(It(a), It(a + 4)), SubRange(It(b), It(b + 5)));
+ auto iter1 = r.begin();
+ auto iter2 = iter1 + 1;
+ using Iter = decltype(iter1);
+ static_assert(std::three_way_comparable<Iter>);
+ compareOperatorTest(iter1, iter2);
+ spaceshipTest(iter1, iter2);
+ }
+
+ {
+ // Test an old-school iterator with no operator<=>; the transform iterator shouldn't have
+ // operator<=> either.
+ using It = random_access_iterator<int*>;
+ using Subrange = std::ranges::subrange<It>;
+ static_assert(!std::three_way_comparable<It>);
+
+ int a[] = {1, 2, 3, 4};
+ int b[] = {5, 6, 7, 8, 9};
+ auto r = std::views::zip_transform(MakeTuple{}, Subrange(It(a), It(a + 4)), Subrange(It(b), It(b + 5)));
+ auto iter1 = r.begin();
+ auto iter2 = iter1 + 1;
+
+ compareOperatorTest(iter1, iter2);
+ spaceshipTest(iter1, iter2);
+ }
+
+ int buffer[5] = {1, 2, 3, 4, 5};
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer});
+ auto it = v.begin();
+ auto it2 = it + 3;
+ compareOperatorTest(it, it2);
+ spaceshipTest(it, it2);
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, SimpleCommon{buffer}, std::views::iota(0));
+ auto it = v.begin();
+ auto it2 = it + 3;
+ compareOperatorTest(it, it2);
+ spaceshipTest(it, it2);
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(Tie{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::single_view(2.));
+ auto it = v.begin();
+ auto it2 = it + 1;
+ compareOperatorTest(it, it2);
+ spaceshipTest(it, it2);
+ }
+
+ {
+ // single empty range
+ std::ranges::zip_transform_view v(MakeTuple{}, std::ranges::empty_view<int>());
+ auto it = v.begin();
+ auto it2 = v.end();
+ assert(it == it2);
+ assert(it <=> it2 == std::strong_ordering::equal);
+ }
+
+ {
+ // empty range at the beginning
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, std::ranges::empty_view<int>(), SimpleCommon{buffer}, SimpleCommon{buffer});
+ auto it = v.begin();
+ auto it2 = v.end();
+ assert(it == it2);
+ assert(it <=> it2 == std::strong_ordering::equal);
+ }
+
+ {
+ // empty range in the middle
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, std::ranges::empty_view<int>(), SimpleCommon{buffer});
+ auto it = v.begin();
+ auto it2 = v.end();
+ assert(it == it2);
+ assert(it <=> it2 == std::strong_ordering::equal);
+ }
+
+ {
+ // empty range at the end
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::empty_view<int>());
+ auto it = v.begin();
+ auto it2 = v.end();
+ assert(it == it2);
+ assert(it <=> it2 == std::strong_ordering::equal);
+ }
+
+ {
+ // non random_access_range
+ int buffer1[1] = {1};
+ int buffer2[2] = {1, 2};
+
+ std::ranges::zip_transform_view v{MakeTuple{}, InputCommonView(buffer1), InputCommonView(buffer2)};
+ using ZTV = decltype(v);
+ static_assert(!std::ranges::forward_range<ZTV>);
+ static_assert(std::ranges::input_range<ZTV>);
+ static_assert(std::ranges::common_range<ZTV>);
+
+ auto it1 = v.begin();
+ auto it2 = v.end();
+ assert(it1 != it2);
+
+ ++it1;
+ assert(it1 == it2);
+
+ inequalityOperatorsDoNotExistTest(it1, it2);
+ }
+
+ {
+ // in this case sentinel is computed by getting each of the underlying sentinel, so only one
+ // underlying iterator is comparing equal
+ int buffer1[1] = {1};
+ int buffer2[2] = {1, 2};
+ std::ranges::zip_transform_view v{MakeTuple{}, ForwardSizedView(buffer1), ForwardSizedView(buffer2)};
+ using ZTV = decltype(v);
+ static_assert(std::ranges::common_range<ZTV>);
+ static_assert(!std::ranges::bidirectional_range<ZTV>);
+
+ auto it1 = v.begin();
+ auto it2 = v.end();
+ assert(it1 != it2);
+
+ ++it1;
+ // it1: <buffer1 + 1, buffer2 + 1>
+ // it2: <buffer1 + 1, buffer2 + 2>
+ assert(it1 == it2);
+
+ inequalityOperatorsDoNotExistTest(it1, it2);
+ }
+
+ {
+ // underlying iterator does not support ==
+ using IterNoEqualView = BasicView<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>;
+ int buffer2[] = {1};
+ std::ranges::zip_transform_view r(MakeTuple{}, IterNoEqualView{buffer2});
+ auto it = r.begin();
+ using Iter = decltype(it);
+ static_assert(!std::invocable<std::equal_to<>, Iter, Iter>);
+ inequalityOperatorsDoNotExistTest(it, it);
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/ctor.default.pass.cpp
new file mode 100644
index 0000000..8f8369d
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/ctor.default.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
+
+// iterator() = default;
+
+#include <ranges>
+
+#include "../types.h"
+
+struct IterDefaultCtrView : std::ranges::view_base {
+ int* begin() const;
+ int* end() const;
+};
+
+struct IterNoDefaultCtrView : std::ranges::view_base {
+ cpp20_input_iterator<int*> begin() const;
+ sentinel_wrapper<cpp20_input_iterator<int*>> end() const;
+};
+
+template <class... Views>
+using Iter = std::ranges::iterator_t<std::ranges::zip_transform_view<MakeTuple, Views...>>;
+
+static_assert(!std::default_initializable<Iter<IterNoDefaultCtrView>>);
+static_assert(!std::default_initializable<Iter<IterNoDefaultCtrView, IterDefaultCtrView>>);
+static_assert(!std::default_initializable<Iter<IterNoDefaultCtrView, IterNoDefaultCtrView>>);
+static_assert(std::default_initializable<Iter<IterDefaultCtrView>>);
+static_assert(std::default_initializable<Iter<IterDefaultCtrView, IterDefaultCtrView>>);
+
+template <class Fn, class... Views>
+constexpr void test() {
+ using ZipTransformIter = std::ranges::iterator_t<std::ranges::zip_transform_view<Fn, Views...>>;
+ ZipTransformIter iter1 = {};
+ ZipTransformIter iter2;
+ assert(iter1 == iter2);
+}
+
+constexpr bool test() {
+ test<MakeTuple, IterDefaultCtrView>();
+ test<MakeTuple, IterDefaultCtrView, std::ranges::empty_view<int>>();
+ test<MakeTuple, IterDefaultCtrView, std::ranges::iota_view<int>, std::ranges::single_view<int>>();
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/ctor.other.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/ctor.other.pass.cpp
new file mode 100644
index 0000000..c643d83
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/ctor.other.pass.cpp
@@ -0,0 +1,131 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr iterator(iterator<!Const> i)
+// requires Const && convertible_to<ziperator<false>, ziperator<Const>>;
+
+#include <array>
+#include <ranges>
+
+#include <cassert>
+
+#include "../types.h"
+
+using ConstIterIncompatibleView =
+ BasicView<forward_iterator<int*>,
+ forward_iterator<int*>,
+ random_access_iterator<const int*>,
+ random_access_iterator<const int*>>;
+static_assert(!std::convertible_to<std::ranges::iterator_t<ConstIterIncompatibleView>,
+ std::ranges::iterator_t<const ConstIterIncompatibleView>>);
+
+constexpr bool test() {
+ int buffer[3] = {1, 2, 3};
+
+ {
+ std::ranges::zip_transform_view v(MakeTuple{}, NonSimpleCommon{buffer});
+ auto iter1 = v.begin();
+ std::ranges::iterator_t<const decltype(v)> iter2 = iter1;
+ assert(iter1 == iter2);
+
+ static_assert(!std::is_same_v<decltype(iter1), decltype(iter2)>);
+
+ // We cannot create a non-const iterator from a const iterator.
+ static_assert(!std::constructible_from<decltype(iter1), decltype(iter2)>);
+ }
+
+ {
+ // Check when we can't perform a non-const-to-const conversion of the ziperator
+ std::ranges::zip_transform_view v(MakeTuple{}, ConstIterIncompatibleView{buffer});
+ auto iter1 = v.begin();
+ auto iter2 = std::as_const(v).begin();
+
+ static_assert(!std::is_same_v<decltype(iter1), decltype(iter2)>);
+
+ static_assert(!std::constructible_from<decltype(iter1), decltype(iter2)>);
+ static_assert(!std::constructible_from<decltype(iter2), decltype(iter1)>);
+ }
+
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, NonSimpleCommon{buffer});
+ auto iter1 = v.begin();
+ std::ranges::iterator_t<const decltype(v)> iter2 = iter1;
+ static_assert(!std::is_same_v<decltype(iter1), decltype(iter2)>);
+ assert(*iter2 == std::tuple(1));
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, NonSimpleCommon{buffer}, std::views::iota(0));
+ auto iter1 = v.begin();
+ std::ranges::iterator_t<const decltype(v)> iter2 = iter1;
+ static_assert(!std::is_same_v<decltype(iter1), decltype(iter2)>);
+ assert(*iter2 == 1);
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(
+ Tie{}, NonSimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::single_view(2.));
+ auto iter1 = v.begin();
+ std::ranges::iterator_t<const decltype(v)> iter2 = iter1;
+ static_assert(!std::is_same_v<decltype(iter1), decltype(iter2)>);
+ assert(*iter2 == std::tuple(1, 1, 2.0));
+ }
+
+ {
+ // single empty range
+ std::array<int, 0> buffer2{};
+ std::ranges::zip_transform_view v(MakeTuple{}, buffer2);
+ auto iter1 = v.begin();
+ std::ranges::iterator_t<const decltype(v)> iter2 = iter1;
+ static_assert(!std::is_same_v<decltype(iter1), decltype(iter2)>);
+ assert(iter2 == v.end());
+ }
+
+ {
+ // empty range at the beginning
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, std::ranges::empty_view<int>(), NonSimpleCommon{buffer}, SimpleCommon{buffer});
+ auto iter1 = v.begin();
+ std::ranges::iterator_t<const decltype(v)> iter2 = iter1;
+ static_assert(!std::is_same_v<decltype(iter1), decltype(iter2)>);
+ assert(iter2 == v.end());
+ }
+
+ {
+ // empty range in the middle
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, std::ranges::empty_view<int>(), NonSimpleCommon{buffer});
+ auto iter1 = v.begin();
+ std::ranges::iterator_t<const decltype(v)> iter2 = iter1;
+ static_assert(!std::is_same_v<decltype(iter1), decltype(iter2)>);
+ assert(iter2 == v.end());
+ }
+
+ {
+ // empty range at the end
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, NonSimpleCommon{buffer}, std::ranges::empty_view<int>());
+ auto iter1 = v.begin();
+ std::ranges::iterator_t<const decltype(v)> iter2 = iter1;
+ static_assert(!std::is_same_v<decltype(iter1), decltype(iter2)>);
+ assert(iter2 == v.end());
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/decrement.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/decrement.pass.cpp
new file mode 100644
index 0000000..9f3647b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/decrement.pass.cpp
@@ -0,0 +1,139 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr iterator& operator--() requires bidirectional_range<Base>;
+// constexpr iterator operator--(int) requires bidirectional_range<Base>;
+
+#include <array>
+#include <cassert>
+#include <ranges>
+
+#include "../types.h"
+
+template <class Iter>
+concept canDecrement = requires(Iter it) { --it; } || requires(Iter it) { it--; };
+
+constexpr bool test() {
+ std::array a{1, 2, 3, 4};
+ std::array b{4.1, 3.2, 4.3};
+ {
+ // all random access
+ std::ranges::zip_transform_view v(MakeTuple{}, a, b, std::views::iota(0, 5));
+ auto it = v.end();
+ using Iter = decltype(it);
+ static_assert(canDecrement<Iter>);
+
+ std::same_as<Iter&> decltype(auto) it_ref = --it;
+ assert(&it_ref == &it);
+
+ assert(*it == std::tuple(3, 4.3, 2));
+
+ auto original = it;
+ std::same_as<Iter> decltype(auto) it2 = it--;
+ assert(original == it2);
+ assert(*it == std::tuple(2, 3.2, 1));
+ }
+
+ {
+ // all bidi+
+ int buffer[2] = {1, 2};
+
+ std::ranges::zip_transform_view v(MakeTuple{}, BidiCommonView{buffer}, std::views::iota(0, 5));
+ auto it = v.begin();
+ using Iter = decltype(it);
+ static_assert(canDecrement<Iter>);
+
+ ++it;
+ ++it;
+
+ std::same_as<Iter&> decltype(auto) it_ref = --it;
+ assert(&it_ref == &it);
+
+ assert(it == ++v.begin());
+ assert(*it == std::tuple(2, 1));
+
+ auto original = it;
+ std::same_as<Iter> decltype(auto) it2 = it--;
+ assert(original == it2);
+ assert(*it == std::tuple(1, 0));
+ }
+
+ {
+ // non bidi
+ int buffer[3] = {4, 5, 6};
+ std::ranges::zip_transform_view v(MakeTuple{}, a, InputCommonView{buffer});
+ using Iter = std::ranges::iterator_t<decltype(v)>;
+ static_assert(!canDecrement<Iter>);
+ }
+
+ int buffer[] = {1, 2, 3, 4, 5, 6};
+
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer});
+ auto it = v.end();
+ using Iter = decltype(it);
+
+ std::same_as<Iter&> decltype(auto) it_ref = --it;
+ assert(&it_ref == &it);
+
+ assert(*it == std::tuple(6));
+
+ auto original = it;
+ std::same_as<Iter> decltype(auto) it2 = it--;
+ assert(original == it2);
+ assert(*it == std::tuple(5));
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, SimpleCommon{buffer}, std::views::iota(0));
+ auto it = v.begin() + 5;
+ using Iter = decltype(it);
+
+ std::same_as<Iter&> decltype(auto) it_ref = --it;
+ assert(&it_ref == &it);
+
+ assert(*it == 5);
+
+ auto original = it;
+ std::same_as<Iter> decltype(auto) it2 = it--;
+ assert(original == it2);
+ assert(*it == 4);
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(Tie{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::single_view(2.));
+ auto it = v.end();
+ using Iter = decltype(it);
+
+ std::same_as<Iter&> decltype(auto) it_ref = --it;
+ assert(&it_ref == &it);
+
+ assert(*it == std::tuple(1, 1, 2.0));
+
+ ++it;
+
+ auto original = it;
+ std::same_as<Iter> decltype(auto) it2 = it--;
+ assert(original == it2);
+ assert(*it == std::tuple(1, 1, 2.0));
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/deref.pass.cpp
new file mode 100644
index 0000000..3c97e11
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/deref.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
+
+// constexpr decltype(auto) operator*() const noexcept(see below);
+
+#include <array>
+#include <cassert>
+#include <ranges>
+
+#include "../types.h"
+
+// Test noexcept
+// Remarks: Let Is be the pack 0, 1, ..., (sizeof...(Views)-1). The exception specification is equivalent to:
+// noexcept(invoke(*parent_->fun_, *std::get<Is>(inner_.current_)...)).
+
+template <class ZipTransformView>
+concept DerefNoexcept = requires(std::ranges::iterator_t<ZipTransformView> iter) { requires noexcept(*iter); };
+
+struct ThrowingDerefIter {
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = int;
+ using difference_type = std::intptr_t;
+
+ int operator*() const noexcept(false);
+
+ ThrowingDerefIter& operator++();
+ void operator++(int);
+
+ friend constexpr bool operator==(const ThrowingDerefIter&, const ThrowingDerefIter&) = default;
+};
+
+using NoexceptDerefIter = int*;
+
+template <bool NoExceptDeref>
+struct TestView : std::ranges::view_base {
+ using Iter = std::conditional_t<NoExceptDeref, NoexceptDerefIter, ThrowingDerefIter>;
+ Iter begin() const;
+ Iter end() const;
+};
+
+template <bool NoExceptCall>
+struct TestFn {
+ int operator()(auto&&...) const noexcept(NoExceptCall);
+};
+
+static_assert(DerefNoexcept<std::ranges::zip_transform_view<TestFn<true>, TestView<true>>>);
+static_assert(DerefNoexcept<std::ranges::zip_transform_view<TestFn<true>, TestView<true>, TestView<true>>>);
+static_assert(!DerefNoexcept<std::ranges::zip_transform_view<TestFn<true>, TestView<false>>>);
+static_assert(!DerefNoexcept<std::ranges::zip_transform_view<TestFn<false>, TestView<true>>>);
+static_assert(!DerefNoexcept<std::ranges::zip_transform_view<TestFn<false>, TestView<false>>>);
+static_assert(!DerefNoexcept<std::ranges::zip_transform_view<TestFn<false>, TestView<false>, TestView<true>>>);
+static_assert(!DerefNoexcept<std::ranges::zip_transform_view<TestFn<true>, TestView<false>, TestView<true>>>);
+static_assert(!DerefNoexcept<std::ranges::zip_transform_view<TestFn<false>, TestView<false>, TestView<false>>>);
+
+constexpr bool test() {
+ std::array a{1, 2, 3, 4};
+ std::array b{4.1, 3.2, 4.3};
+ {
+ // Function returns reference
+ std::ranges::zip_transform_view v(GetFirst{}, a);
+ auto it = v.begin();
+ std::same_as<int&> decltype(auto) val = *it;
+ assert(&val == &a[0]);
+ }
+
+ {
+ // function returns PRValue
+ std::ranges::zip_transform_view v(MakeTuple{}, a, b);
+ auto it = v.begin();
+ std::same_as<std::tuple<int, double>> decltype(auto) val = *it;
+ assert(val == std::tuple(1, 4.1));
+ }
+
+ {
+ // operator* is const
+ std::ranges::zip_transform_view v(GetFirst{}, a);
+ const auto it = v.begin();
+ std::same_as<int&> decltype(auto) val = *it;
+ assert(&val == &a[0]);
+ }
+
+ {
+ // dereference twice
+ std::ranges::zip_transform_view v(MakeTuple{}, a, b);
+ auto it = v.begin();
+ assert(*it == std::tuple(1, 4.1));
+ assert(*it == std::tuple(1, 4.1));
+ }
+
+ {
+ // back and forth
+ std::ranges::zip_transform_view v(Tie{}, a, b);
+ auto it = v.begin();
+ assert(&std::get<0>(*it) == &a[0]);
+ assert(&std::get<1>(*it) == &b[0]);
+ ++it;
+ assert(&std::get<0>(*it) == &a[1]);
+ assert(&std::get<1>(*it) == &b[1]);
+ --it;
+ assert(&std::get<0>(*it) == &a[0]);
+ assert(&std::get<1>(*it) == &b[0]);
+ }
+
+ int buffer[] = {1, 2, 3, 4, 5, 6};
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer});
+ auto it = v.begin();
+ assert(*it == std::make_tuple(1));
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, SimpleCommon{buffer}, std::views::iota(0));
+ auto it = v.begin();
+ assert(&*it == &buffer[0]);
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(Tie{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::single_view(2.));
+ auto it = v.begin();
+ assert(&std::get<0>(*it) == &buffer[0]);
+ assert(&std::get<1>(*it) == &buffer[0]);
+ assert(std::get<2>(*it) == 2.0);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/increment.pass.cpp
new file mode 100644
index 0000000..4a1ec74
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/increment.pass.cpp
@@ -0,0 +1,133 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr iterator& operator++();
+// constexpr void operator++(int);
+// constexpr iterator operator++(int) requires forward_range<Base>;;
+
+#include <array>
+#include <cassert>
+#include <ranges>
+
+#include "../types.h"
+
+struct InputRange : IntBufferView {
+ using IntBufferView::IntBufferView;
+ using iterator = cpp20_input_iterator<int*>;
+ constexpr iterator begin() const { return iterator(buffer_); }
+ constexpr sentinel_wrapper<iterator> end() const { return sentinel_wrapper<iterator>(iterator(buffer_ + size_)); }
+};
+
+template <class View>
+constexpr void testForwardPlus() {
+ int buffer[] = {1, 2, 3, 4};
+
+ std::ranges::zip_transform_view v(GetFirst{}, View{buffer}, View{buffer});
+ auto it = v.begin();
+ using Iter = decltype(it);
+
+ assert(&(*it) == &(buffer[0]));
+
+ std::same_as<Iter&> decltype(auto) it_ref = ++it;
+ assert(&it_ref == &it);
+ assert(&(*it) == &(buffer[1]));
+
+ static_assert(std::is_same_v<decltype(it++), Iter>);
+ auto original = it;
+ std::same_as<Iter> decltype(auto) copy = it++;
+ assert(original == copy);
+ assert(&(*it) == &(buffer[2]));
+}
+
+constexpr bool test() {
+ testForwardPlus<SizedRandomAccessView>();
+ testForwardPlus<BidiCommonView>();
+ testForwardPlus<ForwardSizedView>();
+
+ {
+ // test input_range
+ int buffer[3] = {4, 5, 6};
+ std::ranges::zip_transform_view v(MakeTuple{}, InputRange{buffer}, InputRange{buffer});
+ auto it = v.begin();
+ using Iter = decltype(it);
+
+ assert(*it == std::tuple(4, 4));
+
+ std::same_as<Iter&> decltype(auto) it_ref = ++it;
+ assert(&it_ref == &it);
+ assert(*it == std::tuple(5, 5));
+
+ static_assert(std::is_same_v<decltype(it++), void>);
+ it++;
+ assert(*it == std::tuple(6, 6));
+ }
+
+ int buffer[] = {1, 2, 3, 4, 5, 6};
+
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer});
+ auto it = v.begin();
+ using Iter = decltype(it);
+
+ std::same_as<Iter&> decltype(auto) it_ref = ++it;
+ assert(&it_ref == &it);
+
+ assert(*it == std::tuple(2));
+
+ auto original = it;
+ std::same_as<Iter> decltype(auto) it2 = it++;
+ assert(original == it2);
+ assert(*it == std::tuple(3));
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, SimpleCommon{buffer}, std::views::iota(0));
+ auto it = v.begin();
+ using Iter = decltype(it);
+
+ std::same_as<Iter&> decltype(auto) it_ref = ++it;
+ assert(&it_ref == &it);
+
+ assert(*it == 2);
+
+ auto original = it;
+ std::same_as<Iter> decltype(auto) it2 = it++;
+ assert(original == it2);
+ assert(*it == 3);
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(Tie{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::repeat_view(2.));
+ auto it = v.begin();
+ using Iter = decltype(it);
+
+ std::same_as<Iter&> decltype(auto) it_ref = ++it;
+ assert(&it_ref == &it);
+
+ assert(*it == std::tuple(2, 2, 2.0));
+
+ auto original = it;
+ std::same_as<Iter> decltype(auto) it2 = it++;
+ assert(original == it2);
+ assert(*it == std::tuple(3, 3, 2.0));
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/member_types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/member_types.compile.pass.cpp
new file mode 100644
index 0000000..222f9e4
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/member_types.compile.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
+
+// Iterator traits and member typedefs in zip_transform_view::iterator.
+
+#include <array>
+#include <ranges>
+
+#include "test_iterators.h"
+
+#include "../types.h"
+
+template <class T>
+concept HasIterCategory = requires { typename T::iterator_category; };
+
+template <class T>
+struct DiffTypeIter {
+ using iterator_category = std::input_iterator_tag;
+ using value_type = int;
+ using difference_type = T;
+
+ int operator*() const;
+ DiffTypeIter& operator++();
+ void operator++(int);
+ friend constexpr bool operator==(DiffTypeIter, DiffTypeIter) = default;
+};
+
+template <class T>
+struct DiffTypeRange {
+ DiffTypeIter<T> begin() const;
+ DiffTypeIter<T> end() const;
+};
+
+struct Foo {};
+struct Bar {};
+
+struct RValueRefFn {
+ int&& operator()(auto&&...) const;
+};
+
+void test() {
+ int buffer[] = {1, 2, 3, 4};
+ {
+ // C++20 random_access C++17 random_access
+ std::ranges::zip_transform_view v(GetFirst{}, buffer);
+ using Iter = decltype(v.begin());
+
+ static_assert(std::is_same_v<Iter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::is_same_v<Iter::iterator_category, std::random_access_iterator_tag>);
+ static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>);
+ static_assert(std::is_same_v<Iter::value_type, int>);
+ static_assert(HasIterCategory<Iter>);
+ }
+
+ {
+ // C++20 random_access C++17 input
+ std::ranges::zip_transform_view v(MakeTuple{}, buffer);
+ using Iter = decltype(v.begin());
+
+ static_assert(std::is_same_v<Iter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::is_same_v<Iter::iterator_category, std::input_iterator_tag>);
+ static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>);
+ static_assert(std::is_same_v<Iter::value_type, std::tuple<int>>);
+ static_assert(HasIterCategory<Iter>);
+ }
+
+ {
+ // C++20 bidirectional C++17 bidirectional
+ std::ranges::zip_transform_view v(GetFirst{}, BidiCommonView{buffer});
+ using Iter = decltype(v.begin());
+
+ static_assert(std::is_same_v<Iter::iterator_concept, std::bidirectional_iterator_tag>);
+ static_assert(std::is_same_v<Iter::iterator_category, std::bidirectional_iterator_tag>);
+ static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>);
+ static_assert(std::is_same_v<Iter::value_type, int>);
+ static_assert(HasIterCategory<Iter>);
+ }
+
+ {
+ // C++20 bidirectional C++17 input
+ std::ranges::zip_transform_view v(MakeTuple{}, BidiCommonView{buffer});
+ using Iter = decltype(v.begin());
+
+ static_assert(std::is_same_v<Iter::iterator_concept, std::bidirectional_iterator_tag>);
+ static_assert(std::is_same_v<Iter::iterator_category, std::input_iterator_tag>);
+ static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>);
+ static_assert(std::is_same_v<Iter::value_type, std::tuple<int>>);
+ static_assert(HasIterCategory<Iter>);
+ }
+
+ {
+ // C++20 forward C++17 bidirectional
+ std::ranges::zip_transform_view v(GetFirst{}, ForwardSizedView{buffer});
+ using Iter = decltype(v.begin());
+
+ static_assert(std::is_same_v<Iter::iterator_concept, std::forward_iterator_tag>);
+ static_assert(std::is_same_v<Iter::iterator_category, std::forward_iterator_tag>);
+ static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>);
+ static_assert(std::is_same_v<Iter::value_type, int>);
+ static_assert(HasIterCategory<Iter>);
+ }
+
+ {
+ // C++20 forward C++17 input
+ std::ranges::zip_transform_view v(MakeTuple{}, ForwardSizedView{buffer});
+ using Iter = decltype(v.begin());
+
+ static_assert(std::is_same_v<Iter::iterator_concept, std::forward_iterator_tag>);
+ static_assert(std::is_same_v<Iter::iterator_category, std::input_iterator_tag>);
+ static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>);
+ static_assert(std::is_same_v<Iter::value_type, std::tuple<int>>);
+ static_assert(HasIterCategory<Iter>);
+ }
+
+ {
+ // C++20 input C++17 not a range
+ std::ranges::zip_transform_view v(GetFirst{}, InputCommonView{buffer});
+ using Iter = decltype(v.begin());
+
+ static_assert(std::is_same_v<Iter::iterator_concept, std::input_iterator_tag>);
+ static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>);
+ static_assert(std::is_same_v<Iter::value_type, int>);
+ static_assert(!HasIterCategory<Iter>);
+ }
+
+ {
+ // difference_type of one view
+ std::ranges::zip_transform_view v{MakeTuple{}, DiffTypeRange<std::intptr_t>{}};
+ using Iter = decltype(v.begin());
+ static_assert(std::is_same_v<Iter::difference_type, std::intptr_t>);
+ }
+
+ {
+ // difference_type of multiple views should be the common type
+ std::ranges::zip_transform_view v{MakeTuple{}, DiffTypeRange<std::intptr_t>{}, DiffTypeRange<std::ptrdiff_t>{}};
+ using Iter = decltype(v.begin());
+ static_assert(std::is_same_v<Iter::difference_type, std::common_type_t<std::intptr_t, std::ptrdiff_t>>);
+ }
+
+ const std::array foos{Foo{}};
+ std::array bars{Bar{}, Bar{}};
+ {
+ // value_type of one view
+ std::ranges::zip_transform_view v{MakeTuple{}, foos};
+ using Iter = decltype(v.begin());
+ static_assert(std::is_same_v<Iter::value_type, std::tuple<Foo>>);
+ }
+
+ {
+ // value_type of multiple views with different value_type
+ std::ranges::zip_transform_view v{MakeTuple{}, foos, bars};
+ using Iter = decltype(v.begin());
+ static_assert(std::is_same_v<Iter::value_type, std::tuple<Foo, Bar>>);
+ }
+
+ // LWG3798 Rvalue reference and iterator_category
+ {
+ std::ranges::zip_transform_view v(RValueRefFn{}, buffer);
+ using Iter = decltype(v.begin());
+ static_assert(std::is_same_v<Iter::iterator_category, std::random_access_iterator_tag>);
+ }
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/subscript.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/subscript.pass.cpp
new file mode 100644
index 0000000..70cf811
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/iterator/subscript.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
+
+// constexpr decltype(auto) operator[](difference_type n) const
+// requires random_access_range<Base>;
+
+#include <ranges>
+#include <cassert>
+
+#include "../types.h"
+
+template <class T>
+concept CanSubscript = requires(T t) { t[0]; };
+
+constexpr bool test() {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ {
+ // F returns PR value
+ std::ranges::zip_transform_view v(MakeTuple{}, SizedRandomAccessView{buffer}, std::views::iota(0));
+ auto it = v.begin();
+ using Iter = decltype(it);
+ static_assert(CanSubscript<Iter>);
+
+ std::same_as<std::tuple<int, int>> decltype(auto) val = it[0];
+ assert(val == *it);
+ assert(it[2] == *(it + 2));
+ assert(it[4] == *(it + 4));
+ }
+
+ {
+ // F return by reference
+ std::ranges::zip_transform_view v(GetFirst{}, ContiguousCommonView{buffer}, ContiguousCommonView{buffer});
+ auto it = v.begin();
+ using Iter = decltype(it);
+ static_assert(CanSubscript<Iter>);
+
+ std::same_as<int&> decltype(auto) val = it[0];
+ assert(&val == &buffer[0]);
+ assert(val == *it);
+ assert(it[2] == *(it + 2));
+ assert(it[4] == *(it + 4));
+ }
+
+ {
+ // non random_access_range
+ std::ranges::zip_transform_view v(GetFirst{}, BidiCommonView{buffer});
+ auto it = v.begin();
+ using Iter = decltype(it);
+ static_assert(!CanSubscript<Iter>);
+ }
+
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer});
+ auto it = v.begin();
+ assert(it[2] == std::make_tuple(3));
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, SimpleCommon{buffer}, std::views::iota(0));
+ auto it = v.begin();
+ assert(it[0] == 1);
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(Tie{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::repeat_view(2.));
+ auto it = v.begin();
+ assert(&std::get<0>(it[1]) == &buffer[1]);
+ assert(&std::get<1>(it[2]) == &buffer[2]);
+ assert(std::get<2>(it[3]) == 2.0);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/ctor.default.pass.cpp
new file mode 100644
index 0000000..ab00663
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/ctor.default.pass.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
+
+// sentinel() = default;
+
+#include <cassert>
+#include <ranges>
+
+#include "../types.h"
+
+struct PODSentinel {
+ bool b; // deliberately uninitialised
+
+ friend constexpr bool operator==(int*, const PODSentinel& s) { return s.b; }
+};
+
+struct Fn {
+ int operator()(auto&&...) const { return 5; }
+};
+
+struct Range : std::ranges::view_base {
+ int* begin() const;
+ PODSentinel end();
+};
+
+constexpr bool test() {
+ {
+ using R = std::ranges::zip_transform_view<Fn, Range>;
+ using Sentinel = std::ranges::sentinel_t<R>;
+ static_assert(!std::is_same_v<Sentinel, std::ranges::iterator_t<R>>);
+
+ std::ranges::iterator_t<R> it;
+
+ Sentinel s1;
+ assert(it != s1); // PODSentinel.b is initialised to false
+
+ Sentinel s2 = {};
+ assert(it != s2); // PODSentinel.b is initialised to false
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/ctor.other.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/ctor.other.pass.cpp
new file mode 100644
index 0000000..be7c3d1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/ctor.other.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr sentinel(sentinel<!Const> i)
+// requires Const && convertible_to<zentinel<false>, zentinel<Const>>;
+
+#include <cassert>
+#include <ranges>
+
+#include "../types.h"
+
+template <class T>
+struct convertible_sentinel_wrapper {
+ explicit convertible_sentinel_wrapper() = default;
+ constexpr convertible_sentinel_wrapper(const T& it) : it_(it) {}
+
+ template <class U>
+ requires std::convertible_to<const U&, T>
+ constexpr convertible_sentinel_wrapper(const convertible_sentinel_wrapper<U>& other) : it_(other.it_) {}
+
+ constexpr friend bool operator==(convertible_sentinel_wrapper const& self, const T& other) {
+ return self.it_ == other;
+ }
+ T it_;
+};
+
+struct NonSimpleNonCommonConvertibleView : IntBufferView {
+ using IntBufferView::IntBufferView;
+
+ constexpr int* begin() { return buffer_; }
+ constexpr const int* begin() const { return buffer_; }
+ constexpr convertible_sentinel_wrapper<int*> end() { return convertible_sentinel_wrapper<int*>(buffer_ + size_); }
+ constexpr convertible_sentinel_wrapper<const int*> end() const {
+ return convertible_sentinel_wrapper<const int*>(buffer_ + size_);
+ }
+};
+
+// convertible_to<zentinel<false>, zentinel<Const>>
+static_assert(std::convertible_to< //
+ std::ranges::sentinel_t<std::ranges::zip_view<NonSimpleNonCommonConvertibleView>>,
+ std::ranges::sentinel_t<std::ranges::zip_view<NonSimpleNonCommonConvertibleView> const>>);
+
+constexpr bool test() {
+ int buffer1[4] = {1, 2, 3, 4};
+ int buffer2[5] = {1, 2, 3, 4, 5};
+ {
+ std::ranges::zip_transform_view v{
+ MakeTuple{}, NonSimpleNonCommonConvertibleView(buffer1), NonSimpleNonCommonConvertibleView(buffer2)};
+ using ZipTransformView = decltype(v);
+ static_assert(!std::ranges::common_range<ZipTransformView>);
+ auto sent1 = v.end();
+ std::ranges::sentinel_t<const ZipTransformView> sent2 = sent1;
+ static_assert(!std::is_same_v<decltype(sent1), decltype(sent2)>);
+
+ assert(v.begin() != sent2);
+ assert(std::as_const(v).begin() != sent2);
+ assert(v.begin() + 4 == sent2);
+ assert(std::as_const(v).begin() + 4 == sent2);
+
+ // Cannot create a non-const iterator from a const iterator.
+ static_assert(!std::constructible_from<decltype(sent1), decltype(sent2)>);
+ }
+
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, NonSimpleNonCommonConvertibleView{buffer1});
+ auto sent1 = v.end();
+ std::ranges::sentinel_t<const decltype(v)> sent2 = sent1;
+ static_assert(!std::is_same_v<decltype(sent1), decltype(sent2)>);
+ assert(v.begin() != sent1);
+ assert(v.begin() != sent2);
+ assert(v.begin() + 4 == sent1);
+ assert(v.begin() + 4 == sent2);
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, NonSimpleNonCommonConvertibleView{buffer1}, std::views::iota(0));
+ auto sent1 = v.end();
+ std::ranges::sentinel_t<const decltype(v)> sent2 = sent1;
+ static_assert(!std::is_same_v<decltype(sent1), decltype(sent2)>);
+ assert(v.begin() != sent1);
+ assert(v.begin() != sent2);
+ assert(v.begin() + 4 == sent1);
+ assert(v.begin() + 4 == sent2);
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(
+ Tie{}, NonSimpleNonCommonConvertibleView{buffer1}, SimpleCommon{buffer1}, std::ranges::single_view(2.));
+ auto sent1 = v.end();
+ std::ranges::sentinel_t<const decltype(v)> sent2 = sent1;
+ static_assert(!std::is_same_v<decltype(sent1), decltype(sent2)>);
+ assert(v.begin() != sent1);
+ assert(v.begin() != sent2);
+ assert(v.begin() + 1 == sent1);
+ assert(v.begin() + 1 == sent2);
+ }
+
+ {
+ // single empty range
+ std::ranges::zip_transform_view v(MakeTuple{}, NonSimpleNonCommonConvertibleView(nullptr, 0));
+ auto sent1 = v.end();
+ std::ranges::sentinel_t<const decltype(v)> sent2 = sent1;
+ static_assert(!std::is_same_v<decltype(sent1), decltype(sent2)>);
+ assert(v.begin() == sent1);
+ assert(v.begin() == sent2);
+ }
+
+ {
+ // empty range at the beginning
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, std::ranges::empty_view<int>(), NonSimpleNonCommonConvertibleView{buffer1}, SimpleCommon{buffer1});
+ auto sent1 = v.end();
+ std::ranges::sentinel_t<const decltype(v)> sent2 = sent1;
+ static_assert(!std::is_same_v<decltype(sent1), decltype(sent2)>);
+ assert(v.begin() == sent1);
+ assert(v.begin() == sent2);
+ }
+
+ {
+ // empty range in the middle
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer1}, std::ranges::empty_view<int>(), NonSimpleNonCommonConvertibleView{buffer1});
+ auto sent1 = v.end();
+ std::ranges::sentinel_t<const decltype(v)> sent2 = sent1;
+ static_assert(!std::is_same_v<decltype(sent1), decltype(sent2)>);
+ assert(v.begin() == sent1);
+ assert(v.begin() == sent2);
+ }
+
+ {
+ // empty range at the end
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer1}, NonSimpleNonCommonConvertibleView{buffer1}, std::ranges::empty_view<int>());
+ auto sent1 = v.end();
+ std::ranges::sentinel_t<const decltype(v)> sent2 = sent1;
+ static_assert(!std::is_same_v<decltype(sent1), decltype(sent2)>);
+ assert(v.begin() == sent1);
+ assert(v.begin() == sent2);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/eq.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/eq.pass.cpp
new file mode 100644
index 0000000..9b20dac
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/eq.pass.cpp
@@ -0,0 +1,199 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.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 OtherConst>
+// requires sentinel_for<zentinel<Const>, ziperator<OtherConst>>
+// friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
+
+#include <cassert>
+#include <compare>
+#include <ranges>
+
+#include "../types.h"
+
+using Iterator = random_access_iterator<int*>;
+using ConstIterator = random_access_iterator<const int*>;
+
+template <bool Const>
+struct ComparableSentinel {
+ using Iter = std::conditional_t<Const, ConstIterator, Iterator>;
+ Iter iter_;
+
+ explicit ComparableSentinel() = default;
+ constexpr explicit ComparableSentinel(const Iter& it) : iter_(it) {}
+
+ constexpr friend bool operator==(const Iterator& i, const ComparableSentinel& s) { return base(i) == base(s.iter_); }
+
+ constexpr friend bool operator==(const ConstIterator& i, const ComparableSentinel& s) {
+ return base(i) == base(s.iter_);
+ }
+};
+
+struct ComparableView : IntBufferView {
+ using IntBufferView::IntBufferView;
+
+ constexpr auto begin() { return Iterator(buffer_); }
+ constexpr auto begin() const { return ConstIterator(buffer_); }
+ constexpr auto end() { return ComparableSentinel<false>(Iterator(buffer_ + size_)); }
+ constexpr auto end() const { return ComparableSentinel<true>(ConstIterator(buffer_ + size_)); }
+};
+
+struct ConstIncompatibleView : std::ranges::view_base {
+ cpp17_input_iterator<int*> begin();
+ forward_iterator<const int*> begin() const;
+ sentinel_wrapper<cpp17_input_iterator<int*>> end();
+ sentinel_wrapper<forward_iterator<const int*>> end() const;
+};
+
+template <class Iter, class Sent>
+concept EqualComparable = std::invocable<std::equal_to<>, const Iter&, const Sent&>;
+
+constexpr bool test() {
+ int buffer1[4] = {1, 2, 3, 4};
+ int buffer2[5] = {1, 2, 3, 4, 5};
+ int buffer3[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ {
+ // const and non-const have different iterator/sentinel types
+ std::ranges::zip_transform_view v{
+ MakeTuple{}, NonSimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)};
+ using ZipTransformView = decltype(v);
+ static_assert(!std::ranges::common_range<ZipTransformView>);
+ static_assert(!simple_view<ZipTransformView>);
+
+ assert(v.begin() != v.end());
+ assert(v.begin() + 4 == v.end());
+
+ // const_iterator (const int*) converted to iterator (int*)
+ assert(v.begin() + 4 == std::as_const(v).end());
+
+ using Iter = std::ranges::iterator_t<decltype(v)>;
+ using ConstIter = std::ranges::iterator_t<const decltype(v)>;
+ static_assert(!std::is_same_v<Iter, ConstIter>);
+ using Sentinel = std::ranges::sentinel_t<decltype(v)>;
+ using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
+ static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
+
+ static_assert(EqualComparable<Iter, Sentinel>);
+ static_assert(!EqualComparable<ConstIter, Sentinel>);
+ static_assert(EqualComparable<Iter, ConstSentinel>);
+ static_assert(EqualComparable<ConstIter, ConstSentinel>);
+ }
+
+ {
+ // underlying const/non-const sentinel can be compared with both const/non-const iterator
+ std::ranges::zip_transform_view v{MakeTuple{}, ComparableView(buffer1), ComparableView(buffer2)};
+ using ZipTransformView = decltype(v);
+ static_assert(!std::ranges::common_range<ZipTransformView>);
+ static_assert(!simple_view<ZipTransformView>);
+
+ assert(v.begin() != v.end());
+ assert(v.begin() + 4 == v.end());
+ assert(std::as_const(v).begin() + 4 == v.end());
+ assert(std::as_const(v).begin() + 4 == std::as_const(v).end());
+ assert(v.begin() + 4 == std::as_const(v).end());
+
+ using Iter = std::ranges::iterator_t<decltype(v)>;
+ using ConstIter = std::ranges::iterator_t<const decltype(v)>;
+ static_assert(!std::is_same_v<Iter, ConstIter>);
+ using Sentinel = std::ranges::sentinel_t<decltype(v)>;
+ using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
+ static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
+
+ static_assert(EqualComparable<Iter, Sentinel>);
+ static_assert(EqualComparable<ConstIter, Sentinel>);
+ static_assert(EqualComparable<Iter, ConstSentinel>);
+ static_assert(EqualComparable<ConstIter, ConstSentinel>);
+ }
+
+ {
+ // underlying const/non-const sentinel cannot be compared with non-const/const iterator
+ std::ranges::zip_transform_view v{MakeTuple{}, ComparableView(buffer1), ConstIncompatibleView{}};
+ using ZipTransformView = decltype(v);
+ static_assert(!std::ranges::common_range<ZipTransformView>);
+ static_assert(!simple_view<ZipTransformView>);
+
+ using Iter = std::ranges::iterator_t<decltype(v)>;
+ using ConstIter = std::ranges::iterator_t<const decltype(v)>;
+ static_assert(!std::is_same_v<Iter, ConstIter>);
+ using Sentinel = std::ranges::sentinel_t<decltype(v)>;
+ using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
+ static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
+
+ static_assert(EqualComparable<Iter, Sentinel>);
+ static_assert(!EqualComparable<ConstIter, Sentinel>);
+ static_assert(!EqualComparable<Iter, ConstSentinel>);
+ static_assert(EqualComparable<ConstIter, ConstSentinel>);
+ }
+
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, ComparableView{buffer1});
+ assert(v.begin() != v.end());
+ assert(v.begin() + 4 == v.end());
+ assert(v.begin() + 4 == std::as_const(v).end());
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, ComparableView{buffer2}, std::views::iota(0));
+ assert(v.begin() != v.end());
+ assert(v.begin() + 5 == v.end());
+ assert(v.begin() + 5 == std::as_const(v).end());
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(
+ Tie{}, ComparableView{buffer1}, SimpleNonCommon{buffer2}, std::ranges::single_view(2.));
+ assert(v.begin() != v.end());
+ assert(v.begin() + 1 == v.end());
+ assert(v.begin() + 1 == std::as_const(v).end());
+ }
+
+ {
+ // single empty range
+ std::ranges::zip_transform_view v(MakeTuple{}, ComparableView(nullptr, 0));
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // empty range at the beginning
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, std::ranges::empty_view<int>(), ComparableView{buffer1}, SimpleCommon{buffer2});
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // empty range in the middle
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer1}, std::ranges::empty_view<int>(), ComparableView{buffer2});
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ {
+ // empty range at the end
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer1}, ComparableView{buffer2}, std::ranges::empty_view<int>());
+ assert(v.begin() == v.end());
+ assert(std::as_const(v).begin() == std::as_const(v).end());
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/minus.pass.cpp
new file mode 100644
index 0000000..fc29a00
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/sentinel/minus.pass.cpp
@@ -0,0 +1,279 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.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 OtherConst>
+// requires sized_sentinel_for<zentinel<Const>, ziperator<OtherConst>>
+// friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>>
+// operator-(const sentinel& x, const iterator<OtherConst>& y);
+
+#include <cassert>
+#include <concepts>
+#include <functional>
+#include <ranges>
+#include <tuple>
+
+#include "../types.h"
+
+template <class Base = int*>
+struct convertible_forward_sized_iterator {
+ Base it_ = nullptr;
+
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = int;
+ using difference_type = std::intptr_t;
+
+ convertible_forward_sized_iterator() = default;
+ constexpr convertible_forward_sized_iterator(Base it) : it_(it) {}
+
+ template <std::convertible_to<Base> U>
+ constexpr convertible_forward_sized_iterator(const convertible_forward_sized_iterator<U>& it) : it_(it.it_) {}
+
+ constexpr decltype(*Base{}) operator*() const { return *it_; }
+
+ constexpr convertible_forward_sized_iterator& operator++() {
+ ++it_;
+ return *this;
+ }
+ constexpr convertible_forward_sized_iterator operator++(int) { return forward_sized_iterator(it_++); }
+
+ friend constexpr bool
+ operator==(const convertible_forward_sized_iterator&, const convertible_forward_sized_iterator&) = default;
+
+ friend constexpr difference_type
+ operator-(const convertible_forward_sized_iterator& x, const convertible_forward_sized_iterator& y) {
+ return x.it_ - y.it_;
+ }
+};
+static_assert(std::forward_iterator<convertible_forward_sized_iterator<>>);
+
+template <class Base>
+struct convertible_sized_sentinel {
+ Base base_;
+ explicit convertible_sized_sentinel() = default;
+ constexpr convertible_sized_sentinel(const Base& it) : base_(it) {}
+
+ template <std::convertible_to<Base> U>
+ constexpr convertible_sized_sentinel(const convertible_sized_sentinel<U>& other) : base_(other.base_) {}
+
+ template <class U>
+ requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>)
+ friend constexpr bool operator==(const convertible_sized_sentinel& s, const U& base) {
+ return s.base_ == base;
+ }
+ template <class U>
+ requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>)
+ friend constexpr auto operator-(const convertible_sized_sentinel& s, const U& i) {
+ return s.base_ - i;
+ }
+
+ template <class U>
+ requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>)
+ friend constexpr auto operator-(const U& i, const convertible_sized_sentinel& s) {
+ return i - s.base_;
+ }
+};
+static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<>>,
+ convertible_forward_sized_iterator<>>);
+static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<const int*>>,
+ convertible_forward_sized_iterator<int*>>);
+static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<int*>>,
+ convertible_forward_sized_iterator<const int*>>);
+
+struct ConstCompatibleForwardSized : IntBufferView {
+ using IntBufferView::IntBufferView;
+
+ using iterator = convertible_forward_sized_iterator<int*>;
+ using const_iterator = convertible_forward_sized_iterator<const int*>;
+
+ constexpr iterator begin() { return {buffer_}; }
+ constexpr const_iterator begin() const { return {buffer_}; }
+ constexpr convertible_sized_sentinel<iterator> end() { return iterator{buffer_ + size_}; }
+ constexpr convertible_sized_sentinel<const_iterator> end() const { return const_iterator{buffer_ + size_}; }
+};
+
+template <class T, class U>
+concept HasMinus = std::invocable<std::minus<>, const T&, const U&>;
+
+template <class T>
+concept SentinelHasMinus = HasMinus<std::ranges::sentinel_t<T>, std::ranges::iterator_t<T>>;
+
+constexpr bool test() {
+ int buffer1[5] = {1, 2, 3, 4, 5};
+ int buffer2[3] = {1, 2, 3};
+
+ {
+ // shortest range
+ std::ranges::zip_transform_view v(MakeTuple{}, std::views::iota(0, 3), ForwardSizedNonCommon(buffer1));
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ auto it = v.begin();
+ auto st = v.end();
+ assert(st - it == 3);
+ assert(st - std::ranges::next(it, 1) == 2);
+
+ assert(it - st == -3);
+ assert(std::ranges::next(it, 1) - st == -2);
+ static_assert(SentinelHasMinus<decltype(v)>);
+ }
+
+ {
+ // underlying sentinel does not model sized_sentinel_for
+ std::ranges::zip_transform_view v(MakeTuple{}, std::views::iota(0), SizedRandomAccessView(buffer1));
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ static_assert(!SentinelHasMinus<decltype(v)>);
+ }
+
+ {
+ // const incompatible:
+ // underlying const sentinels cannot subtract underlying iterators
+ // underlying sentinels cannot subtract underlying const iterators
+ std::ranges::zip_transform_view v(MakeTuple{}, NonSimpleForwardSizedNonCommon{buffer1});
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ static_assert(!simple_view<decltype(v)>);
+
+ using Iter = std::ranges::iterator_t<decltype(v)>;
+ using ConstIter = std::ranges::iterator_t<const decltype(v)>;
+ static_assert(!std::is_same_v<Iter, ConstIter>);
+ using Sentinel = std::ranges::sentinel_t<decltype(v)>;
+ using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
+ static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
+
+ static_assert(HasMinus<Iter, Sentinel>);
+ static_assert(HasMinus<Sentinel, Iter>);
+ static_assert(HasMinus<ConstIter, ConstSentinel>);
+ static_assert(HasMinus<ConstSentinel, ConstIter>);
+ auto it = v.begin();
+ auto const_it = std::as_const(v).begin();
+ auto st = v.end();
+ auto const_st = std::as_const(v).end();
+ assert(it - st == -5);
+ assert(st - it == 5);
+ assert(const_it - const_st == -5);
+ assert(const_st - const_it == 5);
+
+ static_assert(!HasMinus<Iter, ConstSentinel>);
+ static_assert(!HasMinus<ConstSentinel, Iter>);
+ static_assert(!HasMinus<ConstIter, Sentinel>);
+ static_assert(!HasMinus<Sentinel, ConstIter>);
+ }
+
+ {
+ // const compatible allow non-const to const conversion
+ std::ranges::zip_transform_view v(MakeTuple{}, ConstCompatibleForwardSized{buffer1});
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ static_assert(!simple_view<decltype(v)>);
+
+ using Iter = std::ranges::iterator_t<decltype(v)>;
+ using ConstIter = std::ranges::iterator_t<const decltype(v)>;
+ static_assert(!std::is_same_v<Iter, ConstIter>);
+ using Sentinel = std::ranges::sentinel_t<decltype(v)>;
+ using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
+ static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
+
+ static_assert(HasMinus<Iter, Sentinel>);
+ static_assert(HasMinus<Sentinel, Iter>);
+ static_assert(HasMinus<ConstIter, ConstSentinel>);
+ static_assert(HasMinus<ConstSentinel, ConstIter>);
+ static_assert(HasMinus<Iter, ConstSentinel>);
+ static_assert(HasMinus<ConstSentinel, Iter>);
+ static_assert(HasMinus<ConstIter, Sentinel>);
+ static_assert(HasMinus<Sentinel, ConstIter>);
+
+ auto it = v.begin();
+ auto const_it = std::as_const(v).begin();
+ auto st = v.end();
+ auto const_st = std::as_const(v).end();
+
+ assert(it - st == -5);
+ assert(st - it == 5);
+ assert(const_it - const_st == -5);
+ assert(const_st - const_it == 5);
+ assert(it - const_st == -5);
+ assert(const_st - it == 5);
+ assert(const_it - st == -5);
+ assert(st - const_it == 5);
+ }
+
+ auto testMinus = [](auto&& v, auto distance) {
+ auto it = v.begin();
+ auto const_it = std::as_const(v).begin();
+ auto st = v.end();
+ auto const_st = std::as_const(v).end();
+
+ assert(it - st == -distance);
+ assert(st - it == distance);
+ assert(const_it - const_st == -distance);
+ assert(const_st - const_it == distance);
+ assert(it - const_st == -distance);
+ assert(const_st - it == distance);
+ assert(const_it - st == -distance);
+ assert(st - const_it == distance);
+ };
+
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, ConstCompatibleForwardSized{buffer1});
+ testMinus(v, 5);
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, ConstCompatibleForwardSized{buffer1}, std::views::iota(0, 100));
+ testMinus(v, 5);
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(
+ Tie{},
+ ConstCompatibleForwardSized{buffer1},
+ ConstCompatibleForwardSized{buffer2},
+ std::ranges::single_view(2.));
+ testMinus(v, 1);
+ }
+
+ {
+ // single empty range
+ std::ranges::zip_transform_view v(MakeTuple{}, ConstCompatibleForwardSized(nullptr, 0));
+ testMinus(v, 0);
+ }
+
+ {
+ // empty range at the beginning
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, std::ranges::empty_view<int>(), ConstCompatibleForwardSized{buffer1}, SimpleCommon{buffer2});
+ testMinus(v, 0);
+ }
+
+ {
+ // empty range in the middle
+ std::ranges::zip_transform_view v(
+ MakeTuple{},
+ ConstCompatibleForwardSized{buffer1},
+ std::ranges::empty_view<int>(),
+ ConstCompatibleForwardSized{buffer2});
+ testMinus(v, 0);
+ }
+
+ {
+ // empty range at the end
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer1}, ConstCompatibleForwardSized{buffer2}, std::ranges::empty_view<int>());
+ testMinus(v, 0);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/size.pass.cpp
new file mode 100644
index 0000000..140bdc3
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/size.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
+
+// constexpr auto size() requires sized_range<InnerView>
+// constexpr auto size() const requires sized_range<const InnerView>
+
+#include <ranges>
+
+#include <cassert>
+
+#include "test_iterators.h"
+#include "types.h"
+
+int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+struct SizedView : std::ranges::view_base {
+ std::size_t size_ = 0;
+ constexpr SizedView(std::size_t s) : size_(s) {}
+ constexpr auto begin() const { return buffer; }
+ constexpr auto end() const { return buffer + size_; }
+};
+
+struct SizedNonConst : std::ranges::view_base {
+ using iterator = forward_iterator<int*>;
+ std::size_t size_ = 0;
+ constexpr SizedNonConst(std::size_t s) : size_(s) {}
+ constexpr auto begin() const { return iterator{buffer}; }
+ constexpr auto end() const { return iterator{buffer + size_}; }
+ constexpr std::size_t size() { return size_; }
+};
+
+struct ConstNonConstDifferentSize : std::ranges::view_base {
+ constexpr auto begin() const { return buffer; }
+ constexpr auto end() const { return buffer + 8; }
+
+ constexpr auto size() { return 5; }
+ constexpr auto size() const { return 6; }
+};
+
+constexpr bool test() {
+ {
+ // one range
+ std::ranges::zip_transform_view v(MakeTuple{}, SimpleCommon{buffer});
+ assert(v.size() == 9);
+ assert(std::as_const(v).size() == 9);
+ }
+
+ {
+ // two ranges
+ std::ranges::zip_transform_view v(GetFirst{}, SimpleCommon{buffer}, SizedView(3));
+ assert(v.size() == 3);
+ assert(std::as_const(v).size() == 3);
+ }
+
+ {
+ // three ranges
+ std::ranges::zip_transform_view v(Tie{}, SimpleCommon{buffer}, SizedView{6}, std::ranges::single_view(2.));
+ assert(v.size() == 1);
+ assert(std::as_const(v).size() == 1);
+ }
+
+ {
+ // single empty range
+ std::ranges::zip_transform_view v(MakeTuple{}, std::ranges::empty_view<int>());
+ assert(v.size() == 0);
+ assert(std::as_const(v).size() == 0);
+ }
+
+ {
+ // empty range at the beginning
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, std::ranges::empty_view<int>(), SimpleCommon{buffer}, SimpleCommon{buffer});
+ assert(v.size() == 0);
+ assert(std::as_const(v).size() == 0);
+ }
+
+ {
+ // empty range in the middle
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, std::ranges::empty_view<int>(), SimpleCommon{buffer});
+ assert(v.size() == 0);
+ assert(std::as_const(v).size() == 0);
+ }
+
+ {
+ // empty range at the end
+ std::ranges::zip_transform_view v(
+ MakeTuple{}, SimpleCommon{buffer}, SimpleCommon{buffer}, std::ranges::empty_view<int>());
+ assert(v.size() == 0);
+ assert(std::as_const(v).size() == 0);
+ }
+
+ {
+ // const-view non-sized range
+ std::ranges::zip_transform_view v(MakeTuple{}, SizedNonConst(2), SizedView(3));
+ assert(v.size() == 2);
+ static_assert(std::ranges::sized_range<decltype(v)>);
+ static_assert(!std::ranges::sized_range<decltype(std::as_const(v))>);
+ }
+
+ {
+ // const/non-const has different sizes
+ std::ranges::zip_transform_view v(MakeTuple{}, ConstNonConstDifferentSize{});
+ assert(v.size() == 5);
+ assert(std::as_const(v).size() == 6);
+ }
+
+ {
+ // underlying range not sized
+ std::ranges::zip_transform_view v(MakeTuple{}, InputCommonView{buffer});
+ static_assert(!std::ranges::sized_range<decltype(v)>);
+ static_assert(!std::ranges::sized_range<decltype(std::as_const(v))>);
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip.transform/types.h b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/types.h
new file mode 100644
index 0000000..dc6a40a
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip.transform/types.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_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TRANSFORM_TYPES_H
+#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TRANSFORM_TYPES_H
+
+#include <functional>
+#include <ranges>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "test_range.h"
+#include "../range_adaptor_types.h"
+
+#if TEST_STD_VER <= 20
+# error "range.zip.transform/types.h" can only be included in builds supporting C++20
+#endif
+
+struct IntView : std::ranges::view_base {
+ int* begin() const;
+ int* end() const;
+};
+
+struct MakeTuple {
+ constexpr auto operator()(auto&&... args) const { return std::tuple(std::forward<decltype(args)>(args)...); }
+};
+
+struct Tie {
+ constexpr auto operator()(auto&&... args) const { return std::tie(std::forward<decltype(args)>(args)...); }
+};
+
+struct GetFirst {
+ constexpr decltype(auto) operator()(auto&& first, auto&&...) const { return std::forward<decltype(first)>(first); }
+};
+
+struct NoConstBeginView : std::ranges::view_base {
+ int* begin();
+ int* end();
+};
+
+struct ConstNonConstDifferentView : std::ranges::view_base {
+ int* begin();
+ const int* begin() const;
+ int* end();
+ const int* end() const;
+};
+
+struct NonConstOnlyFn {
+ int operator()(int&) const;
+ int operator()(const int&) const = delete;
+};
+
+#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TRANSFORM_TYPES_H
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/begin.pass.cpp
index 637d776..837ed9e 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/begin.pass.cpp
@@ -18,7 +18,7 @@
#include <tuple>
#include <utility>
-#include "types.h"
+#include "../range_adaptor_types.h"
template <class T>
concept HasConstBegin = requires(const T& ct) { ct.begin(); };
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/cpo.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/cpo.pass.cpp
index bdfd58ff..34c81f0 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/cpo.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/cpo.pass.cpp
@@ -18,7 +18,7 @@
#include <type_traits>
#include <utility>
-#include "types.h"
+#include "../range_adaptor_types.h"
static_assert(std::is_invocable_v<decltype((std::views::zip))>);
static_assert(!std::is_invocable_v<decltype((std::views::zip)), int>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/ctor.views.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/ctor.views.pass.cpp
index b4a16de..513d268 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/ctor.views.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/ctor.views.pass.cpp
@@ -13,7 +13,7 @@
#include <ranges>
#include <tuple>
-#include "types.h"
+#include "../range_adaptor_types.h"
template <class T>
void conversion_test(T);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/end.pass.cpp
index b7f6447..7cf9f5f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/end.pass.cpp
@@ -14,7 +14,7 @@
#include <ranges>
#include <tuple>
-#include "types.h"
+#include "../range_adaptor_types.h"
// ID | simple | common | bidi | random | sized | #views | v.end() | as_const(v)
// | | | | access | | | | .end()
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/arithmetic.pass.cpp
index efe64b3..444f3ed 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/arithmetic.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/arithmetic.pass.cpp
@@ -25,7 +25,7 @@
#include <concepts>
#include <functional>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
template <class T, class U>
concept canPlusEqual = requires(T& t, U& u) { t += u; };
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/compare.pass.cpp
index 8ab7346..5ad054c 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/compare.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/compare.pass.cpp
@@ -19,7 +19,7 @@
#include "test_iterators.h"
#include "test_range.h"
-#include "../types.h"
+#include "../../range_adaptor_types.h"
// This is for testing that zip iterator never calls underlying iterator's >, >=, <=, !=.
// The spec indicates that zip iterator's >= is negating zip iterator's < instead of calling underlying iterator's >=.
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/ctor.default.pass.cpp
index 98078b2..abced16 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/ctor.default.pass.cpp
@@ -13,7 +13,7 @@
#include <ranges>
#include <tuple>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
struct PODIter {
int i; // deliberately uninitialised
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/ctor.other.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/ctor.other.pass.cpp
index 7f9784e..6b8b55f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/ctor.other.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/ctor.other.pass.cpp
@@ -17,7 +17,7 @@
#include <cassert>
#include <tuple>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
using ConstIterIncompatibleView = BasicView<forward_iterator<int*>, forward_iterator<int*>,
random_access_iterator<const int*>, random_access_iterator<const int*>>;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/decrement.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/decrement.pass.cpp
index a8422ec..db5a651 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/decrement.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/decrement.pass.cpp
@@ -16,7 +16,7 @@
#include <ranges>
#include <tuple>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
template <class Iter>
concept canDecrement = requires(Iter it) { --it; } || requires(Iter it) { it--; };
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/deref.pass.cpp
index fb58aa2..61495fa 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/deref.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/deref.pass.cpp
@@ -15,7 +15,7 @@
#include <ranges>
#include <tuple>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
constexpr bool test() {
std::array a{1, 2, 3, 4};
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp
index 94d2bd4..d094779 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp
@@ -17,7 +17,7 @@
#include <ranges>
#include <tuple>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
struct InputRange : IntBufferView {
using IntBufferView::IntBufferView;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/iter_move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/iter_move.pass.cpp
index 2926b22..f258809 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/iter_move.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/iter_move.pass.cpp
@@ -16,7 +16,7 @@
#include <ranges>
#include <tuple>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
struct ThrowingMove {
ThrowingMove() = default;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/iter_swap.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/iter_swap.pass.cpp
index bb0ec1c..b12877c 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/iter_swap.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/iter_swap.pass.cpp
@@ -15,7 +15,7 @@
#include <cassert>
#include <ranges>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
struct ThrowingMove {
ThrowingMove() = default;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/member_types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/member_types.compile.pass.cpp
index 2f2f0fc..852ea9b 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/member_types.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/member_types.compile.pass.cpp
@@ -16,7 +16,7 @@
#include "test_iterators.h"
-#include "../types.h"
+#include "../../range_adaptor_types.h"
template <class T>
struct ForwardView : std::ranges::view_base {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/singular.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/singular.pass.cpp
index 0f7e4c4..5cd76e0 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/singular.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/singular.pass.cpp
@@ -16,7 +16,7 @@
#include <tuple>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
struct ThrowOnIncrementIterator {
int* it_;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/subscript.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/subscript.pass.cpp
index ba3abfa2..deeeebf 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/subscript.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/subscript.pass.cpp
@@ -14,7 +14,7 @@
#include <ranges>
#include <cassert>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
constexpr bool test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/range.concept.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/range.concept.compile.pass.cpp
index c74c156..4b8587f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/range.concept.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/range.concept.compile.pass.cpp
@@ -18,7 +18,7 @@
#include <tuple>
#include <utility>
-#include "types.h"
+#include "../range_adaptor_types.h"
void testConceptPair() {
int buffer1[2] = {1, 2};
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/ctor.other.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/ctor.other.pass.cpp
index 11ad73c..c3f50b0 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/ctor.other.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/ctor.other.pass.cpp
@@ -13,7 +13,7 @@
#include <cassert>
#include <ranges>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
template <class T>
struct convertible_sentinel_wrapper {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/eq.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/eq.pass.cpp
index 04542c3..fa26d98 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/eq.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/eq.pass.cpp
@@ -17,7 +17,7 @@
#include <ranges>
#include <tuple>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
#include "test_range.h"
using Iterator = random_access_iterator<int*>;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/minus.pass.cpp
index be0a7ba..bcfa340 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/minus.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/minus.pass.cpp
@@ -26,7 +26,7 @@
#include <ranges>
#include <tuple>
-#include "../types.h"
+#include "../../range_adaptor_types.h"
template <class Base = int*>
struct convertible_forward_sized_iterator {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/size.pass.cpp
index 194b3bd..0c0014c 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/size.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/size.pass.cpp
@@ -18,7 +18,7 @@
#include <utility>
#include "test_iterators.h"
-#include "types.h"
+#include "../range_adaptor_types.h"
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
struct View : std::ranges::view_base {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/types.h b/libcxx/test/std/ranges/range.adaptors/range_adaptor_types.h
index e084dcf..288a78ac 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range_adaptor_types.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TYPES_H
-#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TYPES_H
+#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ADAPTOR_TYPES_H
+#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ADAPTOR_TYPES_H
#include <functional>
#include <ranges>
@@ -17,7 +17,7 @@
#include "test_range.h"
#if TEST_STD_VER <= 20
-# error "range.zip/types.h" can only be included in builds supporting C++20
+# error "range.adaptor/types.h" can only be included in builds supporting C++20
#endif // TEST_STD_VER <= 20
template <class T>
@@ -27,12 +27,14 @@ struct BufferView : std::ranges::view_base {
template <std::size_t N>
constexpr BufferView(T (&b)[N]) : buffer_(b), size_(N) {}
+
+ constexpr BufferView(T* b, std::size_t s) : buffer_(b), size_(s) {}
};
using IntBufferView = BufferView<int>;
template <bool Simple>
-struct Common : IntBufferView {
+struct Common : IntBufferView {
using IntBufferView::IntBufferView;
constexpr int* begin()
@@ -48,10 +50,10 @@ struct Common : IntBufferView {
}
constexpr const int* end() const { return buffer_ + size_; }
};
-using SimpleCommon = Common<true>;
+using SimpleCommon = Common<true>;
using NonSimpleCommon = Common<false>;
-using SimpleCommonRandomAccessSized = SimpleCommon;
+using SimpleCommonRandomAccessSized = SimpleCommon;
using NonSimpleCommonRandomAccessSized = NonSimpleCommon;
static_assert(std::ranges::common_range<Common<true>>);
@@ -64,20 +66,22 @@ template <bool Simple>
struct CommonNonRandom : IntBufferView {
using IntBufferView::IntBufferView;
using const_iterator = forward_iterator<const int*>;
- using iterator = forward_iterator<int*>;
+ using iterator = forward_iterator<int*>;
constexpr iterator begin()
- requires(!Simple) {
+ requires(!Simple)
+ {
return iterator(buffer_);
}
constexpr const_iterator begin() const { return const_iterator(buffer_); }
constexpr iterator end()
- requires(!Simple) {
+ requires(!Simple)
+ {
return iterator(buffer_ + size_);
}
constexpr const_iterator end() const { return const_iterator(buffer_ + size_); }
};
-using SimpleCommonNonRandom = CommonNonRandom<true>;
+using SimpleCommonNonRandom = CommonNonRandom<true>;
using NonSimpleCommonNonRandom = CommonNonRandom<false>;
static_assert(std::ranges::common_range<SimpleCommonNonRandom>);
@@ -90,18 +94,20 @@ template <bool Simple>
struct NonCommon : IntBufferView {
using IntBufferView::IntBufferView;
constexpr int* begin()
- requires(!Simple) {
+ requires(!Simple)
+ {
return buffer_;
}
constexpr const int* begin() const { return buffer_; }
constexpr sentinel_wrapper<int*> end()
- requires(!Simple) {
+ requires(!Simple)
+ {
return sentinel_wrapper<int*>(buffer_ + size_);
}
constexpr sentinel_wrapper<const int*> end() const { return sentinel_wrapper<const int*>(buffer_ + size_); }
};
-using SimpleNonCommon = NonCommon<true>;
+using SimpleNonCommon = NonCommon<true>;
using NonSimpleNonCommon = NonCommon<false>;
static_assert(!std::ranges::common_range<SimpleNonCommon>);
@@ -114,21 +120,23 @@ template <bool Simple>
struct NonCommonSized : IntBufferView {
using IntBufferView::IntBufferView;
constexpr int* begin()
- requires(!Simple) {
+ requires(!Simple)
+ {
return buffer_;
}
constexpr const int* begin() const { return buffer_; }
constexpr sentinel_wrapper<int*> end()
- requires(!Simple) {
+ requires(!Simple)
+ {
return sentinel_wrapper<int*>(buffer_ + size_);
}
constexpr sentinel_wrapper<const int*> end() const { return sentinel_wrapper<const int*>(buffer_ + size_); }
constexpr std::size_t size() const { return size_; }
};
-using SimpleNonCommonSized = NonCommonSized<true>;
+using SimpleNonCommonSized = NonCommonSized<true>;
using SimpleNonCommonRandomAccessSized = SimpleNonCommonSized;
-using NonSimpleNonCommonSized = NonCommonSized<false>;
+using NonSimpleNonCommonSized = NonCommonSized<false>;
using NonSimpleNonCommonRandomAccessSized = NonSimpleNonCommonSized;
static_assert(!std::ranges::common_range<SimpleNonCommonSized>);
@@ -142,15 +150,17 @@ struct NonCommonNonRandom : IntBufferView {
using IntBufferView::IntBufferView;
using const_iterator = forward_iterator<const int*>;
- using iterator = forward_iterator<int*>;
+ using iterator = forward_iterator<int*>;
constexpr iterator begin()
- requires(!Simple) {
+ requires(!Simple)
+ {
return iterator(buffer_);
}
constexpr const_iterator begin() const { return const_iterator(buffer_); }
constexpr sentinel_wrapper<iterator> end()
- requires(!Simple) {
+ requires(!Simple)
+ {
return sentinel_wrapper<iterator>(iterator(buffer_ + size_));
}
constexpr sentinel_wrapper<const_iterator> end() const {
@@ -158,7 +168,7 @@ struct NonCommonNonRandom : IntBufferView {
}
};
-using SimpleNonCommonNonRandom = NonCommonNonRandom<true>;
+using SimpleNonCommonNonRandom = NonCommonNonRandom<true>;
using NonSimpleNonCommonNonRandom = NonCommonNonRandom<false>;
static_assert(!std::ranges::common_range<SimpleNonCommonNonRandom>);
@@ -172,13 +182,15 @@ struct BasicView : IntBufferView {
using IntBufferView::IntBufferView;
constexpr NonConstIter begin()
- requires(!std::is_same_v<Iter, NonConstIter>) {
+ requires(!std::is_same_v<Iter, NonConstIter>)
+ {
return NonConstIter(buffer_);
}
constexpr Iter begin() const { return Iter(buffer_); }
constexpr NonConstSent end()
- requires(!std::is_same_v<Sent, NonConstSent>) {
+ requires(!std::is_same_v<Sent, NonConstSent>)
+ {
if constexpr (std::is_same_v<NonConstIter, NonConstSent>) {
return NonConstIter(buffer_ + size_);
} else {
@@ -200,10 +212,10 @@ struct forward_sized_iterator {
Base it_ = nullptr;
using iterator_category = std::forward_iterator_tag;
- using value_type = int;
- using difference_type = std::intptr_t;
- using pointer = Base;
- using reference = decltype(*Base{});
+ using value_type = int;
+ using difference_type = std::intptr_t;
+ using pointer = Base;
+ using reference = decltype(*Base{});
forward_sized_iterator() = default;
constexpr forward_sized_iterator(Base it) : it_(it) {}
@@ -232,8 +244,11 @@ static_assert(std::ranges::common_range<ForwardSizedView>);
static_assert(!std::ranges::random_access_range<ForwardSizedView>);
static_assert(simple_view<ForwardSizedView>);
-using NonSimpleForwardSizedView = BasicView<forward_sized_iterator<const int*>, forward_sized_iterator<const int*>,
- forward_sized_iterator<int*>, forward_sized_iterator<int*>>;
+using NonSimpleForwardSizedView =
+ BasicView<forward_sized_iterator<const int*>,
+ forward_sized_iterator<const int*>,
+ forward_sized_iterator<int*>,
+ forward_sized_iterator<int*>>;
static_assert(std::ranges::forward_range<NonSimpleForwardSizedView>);
static_assert(std::ranges::sized_range<NonSimpleForwardSizedView>);
static_assert(std::ranges::common_range<NonSimpleForwardSizedView>);
@@ -248,8 +263,10 @@ static_assert(!std::ranges::random_access_range<ForwardSizedNonCommon>);
static_assert(simple_view<ForwardSizedNonCommon>);
using NonSimpleForwardSizedNonCommon =
- BasicView<forward_sized_iterator<const int*>, sized_sentinel<forward_sized_iterator<const int*>>,
- forward_sized_iterator<int*>, sized_sentinel<forward_sized_iterator<int*>>>;
+ BasicView<forward_sized_iterator<const int*>,
+ sized_sentinel<forward_sized_iterator<const int*>>,
+ forward_sized_iterator<int*>,
+ sized_sentinel<forward_sized_iterator<int*>>>;
static_assert(std::ranges::forward_range<NonSimpleForwardSizedNonCommon>);
static_assert(std::ranges::sized_range<NonSimpleForwardSizedNonCommon>);
static_assert(!std::ranges::common_range<NonSimpleForwardSizedNonCommon>);
@@ -278,8 +295,10 @@ static_assert(!std::ranges::sized_range<NonSizedRandomAccessView>);
static_assert(simple_view<NonSizedRandomAccessView>);
using NonSimpleNonSizedRandomAccessView =
- BasicView<random_access_iterator<const int*>, sentinel_wrapper<random_access_iterator<const int*>>,
- random_access_iterator<int*>, sentinel_wrapper<random_access_iterator<int*>> >;
+ BasicView<random_access_iterator<const int*>,
+ sentinel_wrapper<random_access_iterator<const int*>>,
+ random_access_iterator<int*>,
+ sentinel_wrapper<random_access_iterator<int*>> >;
static_assert(!std::ranges::contiguous_range<NonSimpleNonSizedRandomAccessView>);
static_assert(std::ranges::random_access_range<NonSimpleNonSizedRandomAccessView>);
static_assert(!std::ranges::common_range<NonSimpleNonSizedRandomAccessView>);
@@ -308,8 +327,11 @@ static_assert(!std::ranges::forward_range<InputCommonView>);
static_assert(std::ranges::common_range<InputCommonView>);
static_assert(simple_view<InputCommonView>);
-using NonSimpleInputCommonView = BasicView<common_input_iterator<const int*>, common_input_iterator<const int*>,
- common_input_iterator<int*>, common_input_iterator<int*>>;
+using NonSimpleInputCommonView =
+ BasicView<common_input_iterator<const int*>,
+ common_input_iterator<const int*>,
+ common_input_iterator<int*>,
+ common_input_iterator<int*>>;
static_assert(std::ranges::input_range<NonSimpleInputCommonView>);
static_assert(!std::ranges::forward_range<NonSimpleInputCommonView>);
static_assert(std::ranges::common_range<NonSimpleInputCommonView>);
@@ -322,8 +344,10 @@ static_assert(!std::ranges::common_range<InputNonCommonView>);
static_assert(simple_view<InputNonCommonView>);
using NonSimpleInputNonCommonView =
- BasicView<common_input_iterator<const int*>, sentinel_wrapper<common_input_iterator<const int*>>,
- common_input_iterator<int*>, sentinel_wrapper<common_input_iterator<int*>>>;
+ BasicView<common_input_iterator<const int*>,
+ sentinel_wrapper<common_input_iterator<const int*>>,
+ common_input_iterator<int*>,
+ sentinel_wrapper<common_input_iterator<int*>>>;
static_assert(std::ranges::input_range<InputNonCommonView>);
static_assert(!std::ranges::forward_range<InputNonCommonView>);
static_assert(!std::ranges::common_range<InputNonCommonView>);
@@ -336,8 +360,11 @@ static_assert(!std::ranges::random_access_range<BidiCommonView>);
static_assert(std::ranges::common_range<BidiCommonView>);
static_assert(simple_view<BidiCommonView>);
-using NonSimpleBidiCommonView = BasicView<bidirectional_iterator<const int*>, bidirectional_iterator<const int*>,
- bidirectional_iterator<int*>, bidirectional_iterator<int*>>;
+using NonSimpleBidiCommonView =
+ BasicView<bidirectional_iterator<const int*>,
+ bidirectional_iterator<const int*>,
+ bidirectional_iterator<int*>,
+ bidirectional_iterator<int*>>;
static_assert(!std::ranges::sized_range<NonSimpleBidiCommonView>);
static_assert(std::ranges::bidirectional_range<NonSimpleBidiCommonView>);
static_assert(!std::ranges::random_access_range<NonSimpleBidiCommonView>);
@@ -372,8 +399,10 @@ static_assert(!std::ranges::common_range<BidiNonCommonView>);
static_assert(simple_view<BidiNonCommonView>);
using NonSimpleBidiNonCommonView =
- BasicView<bidirectional_iterator<const int*>, sentinel_wrapper<bidirectional_iterator<const int*>>,
- bidirectional_iterator<int*>, sentinel_wrapper<bidirectional_iterator<int*>>>;
+ BasicView<bidirectional_iterator<const int*>,
+ sentinel_wrapper<bidirectional_iterator<const int*>>,
+ bidirectional_iterator<int*>,
+ sentinel_wrapper<bidirectional_iterator<int*>>>;
static_assert(!std::ranges::sized_range<NonSimpleBidiNonCommonView>);
static_assert(std::ranges::bidirectional_range<NonSimpleBidiNonCommonView>);
static_assert(!std::ranges::random_access_range<NonSimpleBidiNonCommonView>);
@@ -388,24 +417,25 @@ static_assert(!std::ranges::common_range<SizedBidiNonCommonView>);
static_assert(simple_view<SizedBidiNonCommonView>);
using NonSimpleSizedBidiNonCommonView =
- BasicView<bidirectional_iterator<const int*>, sized_sentinel<bidirectional_iterator<const int*>>,
- bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
+ BasicView<bidirectional_iterator<const int*>,
+ sized_sentinel<bidirectional_iterator<const int*>>,
+ bidirectional_iterator<int*>,
+ sized_sentinel<bidirectional_iterator<int*>>>;
static_assert(std::ranges::sized_range<NonSimpleSizedBidiNonCommonView>);
static_assert(std::ranges::bidirectional_range<NonSimpleSizedBidiNonCommonView>);
static_assert(!std::ranges::random_access_range<NonSimpleSizedBidiNonCommonView>);
static_assert(!std::ranges::common_range<NonSimpleSizedBidiNonCommonView>);
static_assert(!simple_view<NonSimpleSizedBidiNonCommonView>);
-namespace adltest{
+namespace adltest {
struct iter_move_swap_iterator {
-
std::reference_wrapper<int> iter_move_called_times;
std::reference_wrapper<int> iter_swap_called_times;
int i = 0;
using iterator_category = std::input_iterator_tag;
- using value_type = int;
- using difference_type = std::intptr_t;
+ using value_type = int;
+ using difference_type = std::intptr_t;
constexpr int operator*() const { return i; }
@@ -435,4 +465,4 @@ struct IterMoveSwapRange {
};
} // namespace adltest
-#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TYPES_H
+#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ADAPTOR_TYPES_H
diff --git a/libcxx/test/std/ranges/ranges_robust_against_no_unique_address.pass.cpp b/libcxx/test/std/ranges/ranges_robust_against_no_unique_address.pass.cpp
index 3b35271..0618665 100644
--- a/libcxx/test/std/ranges/ranges_robust_against_no_unique_address.pass.cpp
+++ b/libcxx/test/std/ranges/ranges_robust_against_no_unique_address.pass.cpp
@@ -58,6 +58,7 @@ constexpr bool test() {
#if TEST_STD_VER >= 23
testOne<std::ranges::chunk_by_view<View, Pred>>();
testOne<std::ranges::repeat_view<Pred>>();
+ testOne<std::ranges::zip_transform_view<Pred, View>>();
#endif
return true;
}
diff --git a/libcxx/test/std/re/re.regex/re.regex.construct/bad_range.pass.cpp b/libcxx/test/std/re/re.regex/re.regex.construct/bad_range.pass.cpp
index 023bc0e..ecfdaee 100644
--- a/libcxx/test/std/re/re.regex/re.regex.construct/bad_range.pass.cpp
+++ b/libcxx/test/std/re/re.regex/re.regex.construct/bad_range.pass.cpp
@@ -14,6 +14,8 @@
// template <class ST, class SA>
// basic_regex(const basic_string<charT, ST, SA>& s);
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
#include <regex>
#include <cassert>
#include "test_macros.h"
@@ -33,6 +35,7 @@ int main(int, char**)
{
assert(error_range_thrown("([\\w-a])"));
assert(error_range_thrown("([a-\\w])"));
+ assert(error_range_thrown("([w-a])"));
- return 0;
+ return 0;
}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/shared_ptr_array.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/shared_ptr_array.pass.cpp
index 9ff1482..9bc695c 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/shared_ptr_array.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/shared_ptr_array.pass.cpp
@@ -10,8 +10,6 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// These compiler versions and platforms don't enable sized deallocation by default.
-// ADDITIONAL_COMPILE_FLAGS(clang-17): -fsized-deallocation
-// ADDITIONAL_COMPILE_FLAGS(clang-18): -fsized-deallocation
// ADDITIONAL_COMPILE_FLAGS(apple-clang-16): -fsized-deallocation
// ADDITIONAL_COMPILE_FLAGS(target=x86_64-w64-windows-gnu): -fsized-deallocation
// ADDITIONAL_COMPILE_FLAGS(target=i686-w64-windows-gnu): -fsized-deallocation
diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
index 47c95c6..2e0b1e9 100644
--- a/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
+++ b/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
// These compilers don't support __builtin_is_virtual_base_of yet.
-// UNSUPPORTED: clang-18, clang-19, gcc-14, apple-clang-16, apple-clang-17
+// UNSUPPORTED: clang-19, gcc-14, apple-clang-16, apple-clang-17
// <type_traits>
diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp
index 192943d..b7fd093 100644
--- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// These compilers don't support __builtin_is_implicit_lifetime yet.
-// UNSUPPORTED: clang-18, clang-19, gcc-14, gcc-15, apple-clang-16, apple-clang-17
+// UNSUPPORTED: clang-19, gcc-14, gcc-15, apple-clang-16, apple-clang-17
// <type_traits>
diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp
index e5b10f5..1ca9d44 100644
--- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// These compilers don't support __builtin_is_implicit_lifetime yet.
-// UNSUPPORTED: clang-18, clang-19, gcc-14, apple-clang-16, apple-clang-17
+// UNSUPPORTED: clang-19, gcc-14, apple-clang-16, apple-clang-17
// <type_traits>
diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp
index 03bec8c..ad53c81 100644
--- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: std-at-least-c++23
// These compilers don't support std::reference_converts_from_temporary yet.
-// UNSUPPORTED: android, apple-clang-16, clang-19.1
+// UNSUPPORTED: apple-clang-16, clang-19.1
// <type_traits>
diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp
index 82688b1..73cc4f3 100644
--- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: std-at-least-c++23
// These compilers don't support std::reference_converts_from_temporary yet.
-// UNSUPPORTED: android, apple-clang-16, clang-18, clang-19.1
+// UNSUPPORTED: apple-clang-16, clang-19.1
// <type_traits>
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
index 34b79b3..2c14de8 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
@@ -214,7 +214,7 @@ static constexpr bool can_make_from_tuple =
template <class T, class Tuple>
auto test_make_from_tuple_impl(T&&, Tuple&& t)
-> decltype(std::__make_from_tuple_impl<T>(
- t, typename std::__make_tuple_indices< std::tuple_size_v<std::remove_reference_t<Tuple>>>::type{}),
+ t, typename std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>()),
std::uint8_t()) {
return 0;
}
diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h
index a279400..a091043 100644
--- a/libcxx/test/support/check_assertion.h
+++ b/libcxx/test/support/check_assertion.h
@@ -44,15 +44,32 @@ static constexpr const char* Marker = "###";
using MatchResult = std::pair<bool, std::string>;
using Matcher = std::function<MatchResult(const std::string& /*text*/)>;
-MatchResult MatchAssertionMessage(const std::string& text, std::string_view expected_message) {
+// Using the marker makes matching more precise, but we cannot output the marker when the `observe` semantic is used
+// (because it doesn't allow customizing the logging function). If the marker is not available, fall back to using less
+// precise matching by just the error message.
+MatchResult MatchAssertionMessage(const std::string& text, std::string_view expected_message, bool use_marker) {
// Extract information from the error message. This has to stay synchronized with how we format assertions in the
// library.
- std::regex assertion_format(".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###");
+ std::string assertion_format_string = [&] {
+ if (use_marker)
+ return (".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###");
+ return ("(.*):(\\d+): assertion (.*) failed: (.*)\\n");
+ }();
+ std::regex assertion_format(assertion_format_string);
std::smatch match_result;
- bool has_match = std::regex_match(text, match_result, assertion_format);
- assert(has_match);
- assert(match_result.size() == 5);
+ // If a non-terminating assertion semantic is used, more than one assertion might be triggered before the process
+ // dies, so we cannot expect the entire target string to match.
+ bool has_match = std::regex_search(text, match_result, assertion_format);
+ if (!has_match || match_result.size() != 5) {
+ std::stringstream matching_error;
+ matching_error //
+ << "Failed to parse the assertion message.\n" //
+ << "Using marker: " << use_marker << "\n" //
+ << "Expected message: '" << expected_message.data() << "'\n" //
+ << "Stderr contents: '" << text.c_str() << "'\n";
+ return MatchResult(/*success=*/false, matching_error.str());
+ }
const std::string& file = match_result[1];
int line = std::stoi(match_result[2]);
@@ -72,9 +89,9 @@ MatchResult MatchAssertionMessage(const std::string& text, std::string_view expe
return MatchResult(/*success=*/true, /*maybe_error=*/"");
}
-Matcher MakeAssertionMessageMatcher(std::string_view assertion_message) {
+Matcher MakeAssertionMessageMatcher(std::string_view assertion_message, bool use_marker = true) {
return [=](const std::string& text) { //
- return MatchAssertionMessage(text, assertion_message);
+ return MatchAssertionMessage(text, assertion_message, use_marker);
};
}
@@ -85,13 +102,17 @@ Matcher MakeAnyMatcher() {
}
enum class DeathCause {
- // Valid causes
+ // Valid causes.
VerboseAbort = 1,
StdAbort,
StdTerminate,
Trap,
- // Invalid causes
+ // Causes that might be invalid or might stem from undefined behavior (relevant for non-terminating assertion
+ // semantics).
DidNotDie,
+ Segfault,
+ ArithmeticError,
+ // Always invalid causes.
SetupFailure,
Unknown
};
@@ -108,6 +129,16 @@ bool IsValidCause(DeathCause cause) {
}
}
+bool IsTestSetupErrorCause(DeathCause cause) {
+ switch (cause) {
+ case DeathCause::SetupFailure:
+ case DeathCause::Unknown:
+ return true;
+ default:
+ return false;
+ }
+}
+
std::string ToString(DeathCause cause) {
switch (cause) {
case DeathCause::VerboseAbort:
@@ -120,10 +151,14 @@ std::string ToString(DeathCause cause) {
return "trap";
case DeathCause::DidNotDie:
return "<invalid cause (child did not die)>";
+ case DeathCause::Segfault:
+ return "<invalid cause (segmentation fault)>";
+ case DeathCause::ArithmeticError:
+ return "<invalid cause (fatal arithmetic error)>";
case DeathCause::SetupFailure:
- return "<invalid cause (child failed to set up test environment)>";
+ return "<test setup error (child failed to set up test environment)>";
case DeathCause::Unknown:
- return "<invalid cause (cause unknown)>";
+ return "<test setup error (test doesn't know how to interpret the death cause)>";
}
assert(false && "Unreachable");
@@ -225,9 +260,38 @@ public:
return DeathTestResult(Outcome::Success, cause);
}
- void PrintFailureDetails(std::string_view failure_description, std::string_view stmt, DeathCause cause) const {
- std::fprintf(
- stderr, "Failure: EXPECT_DEATH( %s ) failed!\n(reason: %s)\n\n", stmt.data(), failure_description.data());
+ // When non-terminating assertion semantics are used, the program will invoke UB which might or might not crash the
+ // process; we make sure that the execution produces the expected error message but otherwise consider the test run
+ // successful whether the child process dies or not.
+ template <class Func>
+ DeathTestResult RunWithoutGuaranteedDeath(Func&& func, const Matcher& matcher) {
+ std::signal(SIGABRT, [](int) { StopChildProcess(DeathCause::StdAbort); });
+ std::set_terminate([] { StopChildProcess(DeathCause::StdTerminate); });
+
+ DeathCause cause = Run(func);
+
+ if (IsTestSetupErrorCause(cause)) {
+ return DeathTestResult(Outcome::InvalidCause, cause, ToString(cause));
+ }
+
+ MatchResult match_result = matcher(GetChildStdErr());
+ if (!match_result.first) {
+ auto failure_description = std::string("Child produced a different error message\n") + match_result.second;
+ return DeathTestResult(Outcome::UnexpectedErrorMessage, cause, failure_description);
+ }
+
+ return DeathTestResult(Outcome::Success, cause);
+ }
+
+ void PrintFailureDetails(std::string_view invocation,
+ std::string_view failure_description,
+ std::string_view stmt,
+ DeathCause cause) const {
+ std::fprintf(stderr,
+ "Failure: %s( %s ) failed!\n(reason: %s)\n\n",
+ invocation.data(),
+ stmt.data(),
+ failure_description.data());
if (cause != DeathCause::Unknown) {
std::fprintf(stderr, "child exit code: %d\n", GetChildExitCode());
@@ -311,10 +375,16 @@ private:
if (WIFSIGNALED(status_value)) {
exit_code_ = WTERMSIG(status_value);
- // `__builtin_trap` generqtes `SIGILL` on x86 and `SIGTRAP` on ARM.
+ // `__builtin_trap` generates `SIGILL` on x86 and `SIGTRAP` on ARM.
if (exit_code_ == SIGILL || exit_code_ == SIGTRAP) {
return DeathCause::Trap;
}
+ if (exit_code_ == SIGSEGV) {
+ return DeathCause::Segfault;
+ }
+ if (exit_code_ == SIGFPE) {
+ return DeathCause::ArithmeticError;
+ }
}
return DeathCause::Unknown;
@@ -357,7 +427,7 @@ bool ExpectDeath(
DeathTest test_case;
DeathTestResult test_result = test_case.Run(expected_causes, func, matcher);
if (!test_result.success()) {
- test_case.PrintFailureDetails(test_result.failure_description(), stmt, test_result.cause());
+ test_case.PrintFailureDetails("EXPECT_DEATH", test_result.failure_description(), stmt, test_result.cause());
}
return test_result.success();
@@ -378,6 +448,22 @@ bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) {
return ExpectDeath(std::array<DeathCause, 1>{expected_cause}, stmt, func, MakeAnyMatcher());
}
+template <class Func>
+bool ExpectLog(const char* stmt, Func&& func, const Matcher& matcher) {
+ DeathTest test_case;
+ DeathTestResult test_result = test_case.RunWithoutGuaranteedDeath(func, matcher);
+ if (!test_result.success()) {
+ test_case.PrintFailureDetails("EXPECT_LOG", test_result.failure_description(), stmt, test_result.cause());
+ }
+
+ return test_result.success();
+}
+
+template <class Func>
+bool ExpectLog(const char* stmt, Func&& func) {
+ return ExpectLog(stmt, func, MakeAnyMatcher());
+}
+
// clang-format off
/// Assert that the specified expression aborts with the expected cause and, optionally, error message.
@@ -392,13 +478,28 @@ bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) {
#define EXPECT_STD_TERMINATE(...) \
assert( ExpectDeath(DeathCause::StdTerminate, #__VA_ARGS__, __VA_ARGS__) )
-#if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+#if defined(_LIBCPP_ASSERTION_SEMANTIC)
+
+#if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
assert(( ExpectDeath(DeathCause::VerboseAbort, #expr, [&]() { (void)(expr); }, MakeAssertionMessageMatcher(message)) ))
+#elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
+#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
+ assert(( ExpectDeath(DeathCause::Trap, #expr, [&]() { (void)(expr); }) ))
+#elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_OBSERVE
+#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
+ assert(( ExpectLog(#expr, [&]() { (void)(expr); }, MakeAssertionMessageMatcher(message, /*use_marker=*/false)) ))
+#elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_IGNORE
+#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
+ assert(( ExpectLog(#expr, [&]() { (void)(expr); }) ))
+#else
+#error "Unknown value for _LIBCPP_ASSERTION_SEMANTIC"
+#endif // _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
+
#else
#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
assert(( ExpectDeath(DeathCause::Trap, #expr, [&]() { (void)(expr); }) ))
-#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+#endif // defined(_LIBCPP_ASSERTION_SEMANTIC)
// clang-format on
diff --git a/libcxx/test/support/test.support/test_check_assertion.pass.cpp b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
index 4dfc531..78e47b3 100644
--- a/libcxx/test/support/test.support/test_check_assertion.pass.cpp
+++ b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
@@ -53,7 +53,7 @@ bool TestDeathTest(
}
if (!maybe_failure_description.empty()) {
- test_case.PrintFailureDetails(maybe_failure_description, stmt, test_result.cause());
+ test_case.PrintFailureDetails("EXPECT_DEATH", maybe_failure_description, stmt, test_result.cause());
return false;
}
@@ -76,9 +76,9 @@ DeathCause assertion_death_cause = DeathCause::Trap;
#endif
int main(int, char**) {
- auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); };
- Matcher good_matcher = MakeAssertionMessageMatcher("Some message");
- Matcher bad_matcher = MakeAssertionMessageMatcher("Bad expected message");
+ [[maybe_unused]] auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); };
+ Matcher good_matcher = MakeAssertionMessageMatcher("Some message");
+ Matcher bad_matcher = MakeAssertionMessageMatcher("Bad expected message");
// Test the implementation of death tests. We're bypassing the assertions added by the actual `EXPECT_DEATH` macros
// which allows us to test failure cases (where the assertion would fail) as well.
@@ -89,16 +89,22 @@ int main(int, char**) {
// Success -- trapping.
TEST_DEATH_TEST(Outcome::Success, DeathCause::Trap, __builtin_trap());
+ // `_LIBCPP_ASSERT` does not terminate the program if the `observe` semantic is used, so these tests would fail with
+ // `DidNotDie` cause.
+#if _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE
+
// Success -- assertion failure with any matcher.
TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, MakeAnyMatcher(), fail_assert());
// Success -- assertion failure with a specific matcher.
TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, good_matcher, fail_assert());
-#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
// Failure -- error message doesn't match.
TEST_DEATH_TEST_MATCHES(Outcome::UnexpectedErrorMessage, assertion_death_cause, bad_matcher, fail_assert());
-#endif
+# endif
+
+#endif // _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE
// Invalid cause -- child did not die.
TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::DidNotDie, ((void)0));
@@ -125,7 +131,9 @@ int main(int, char**) {
EXPECT_DEATH_MATCHES(simple_matcher, invoke_verbose_abort());
EXPECT_STD_ABORT(invoke_abort());
EXPECT_STD_TERMINATE([] { std::terminate(); });
+#if _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE
TEST_LIBCPP_ASSERT_FAILURE(fail_assert(), "Some message");
+#endif
}
return 0;
diff --git a/libcxx/utils/ci/Dockerfile b/libcxx/utils/ci/Dockerfile
index 63cecea..79e1156 100644
--- a/libcxx/utils/ci/Dockerfile
+++ b/libcxx/utils/ci/Dockerfile
@@ -38,6 +38,7 @@
# If you're only looking to run the Docker image locally for debugging a
# build bot, see the `run-buildbot-container` script located in this directory.
+ARG ACTIONS_BASE_IMAGE
# HACK: We set the base image in the docker-compose file depending on the final target (buildkite vs github actions).
# This means we have a much slower container build, but we can use the same Dockerfile for both targets.
@@ -309,7 +310,20 @@ CMD /opt/android/container-setup.sh && buildkite-agent start
#
# IMAGE: ghcr.io/libcxx/actions-builder.
#
-FROM builder-base AS actions-builder
-
-WORKDIR /home/runner
-USER runner
+FROM $ACTIONS_BASE_IMAGE AS actions-builder
+
+ARG GITHUB_RUNNER_VERSION
+
+RUN useradd gha -u 1001 -m -s /bin/bash
+RUN adduser gha sudo
+RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
+WORKDIR /home/gha
+USER gha
+
+ENV RUNNER_MANUALLY_TRAP_SIG=1
+ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1
+RUN mkdir actions-runner && \
+ cd actions-runner && \
+ curl -O -L https://github.com/actions/runner/releases/download/v$GITHUB_RUNNER_VERSION/actions-runner-linux-x64-$GITHUB_RUNNER_VERSION.tar.gz && \
+ tar xzf ./actions-runner-linux-x64-$GITHUB_RUNNER_VERSION.tar.gz && \
+ rm ./actions-runner-linux-x64-$GITHUB_RUNNER_VERSION.tar.gz
diff --git a/libcxx/utils/ci/docker-compose.yml b/libcxx/utils/ci/docker-compose.yml
index 4efc6d2..36b8dd7 100644
--- a/libcxx/utils/ci/docker-compose.yml
+++ b/libcxx/utils/ci/docker-compose.yml
@@ -3,6 +3,16 @@ x-versions: &compiler_versions
LLVM_HEAD_VERSION: 21
services:
+ builder-base:
+ image: ghcr.io/llvm/libcxx-linux-builder-base:${TAG}
+ build:
+ context: .
+ dockerfile: Dockerfile
+ target: builder-base
+ args:
+ BASE_IMAGE: ubuntu:jammy
+ <<: *compiler_versions
+
actions-builder:
image: ghcr.io/llvm/libcxx-linux-builder:${TAG}
build:
@@ -10,7 +20,9 @@ services:
dockerfile: Dockerfile
target: actions-builder
args:
- BASE_IMAGE: ghcr.io/actions/actions-runner:2.326.0
+ BASE_IMAGE: ubuntu:jammy
+ ACTIONS_BASE_IMAGE: builder-base
+ GITHUB_RUNNER_VERSION: "2.326.0"
<<: *compiler_versions
android-buildkite-builder:
diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot
index d8b23be..57ecf1e 100755
--- a/libcxx/utils/ci/run-buildbot
+++ b/libcxx/utils/ci/run-buildbot
@@ -442,6 +442,12 @@ generic-hardening-mode-extensive)
check-runtimes
check-abi-list
;;
+generic-hardening-mode-extensive-observe-semantic)
+ clean
+ generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-hardening-mode-extensive-observe-semantic.cmake"
+ check-runtimes
+ check-abi-list
+;;
generic-hardening-mode-debug)
clean
generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-hardening-mode-debug.cmake"
diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py
index adfb2a9..81c6134 100644
--- a/libcxx/utils/libcxx/test/params.py
+++ b/libcxx/utils/libcxx/test/params.py
@@ -361,6 +361,7 @@ DEFAULT_PARAMETERS = [
AddFeature("libcpp-has-no-incomplete-pstl"),
AddFeature("libcpp-has-no-experimental-tzdb"),
AddFeature("libcpp-has-no-experimental-syncstream"),
+ AddFeature("libcpp-has-no-experimental-hardening-observe-semantic"),
],
),
# TODO: This can be improved once we use a version of GoogleBenchmark that supports the dry-run mode.
@@ -454,5 +455,24 @@ DEFAULT_PARAMETERS = [
help="Whether to test the main or C++03-specific headers. Only changes behaviour when std=c++03.",
actions=lambda enabled: [] if not enabled else [AddFlag("-D_LIBCPP_USE_FROZEN_CXX03_HEADERS"), AddFeature("FROZEN-CXX03-HEADERS-FIXME")],
),
+ Parameter(
+ name='assertion_semantic',
+ choices=["ignore", "observe", "quick_enforce", "enforce", "undefined"],
+ type=str,
+ default="undefined",
+ help="Whether to override the assertion semantic used by hardening. This is only meaningful when running the "
+ "tests against libc++ with hardening enabled. By default, no assertion semantic is specified explicitly, so "
+ "the default one will be used (depending on the hardening mode).",
+ actions=lambda assertion_semantic: filter(
+ None,
+ [
+ AddCompileFlag("-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE") if assertion_semantic == "ignore" else None,
+ AddCompileFlag("-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE") if assertion_semantic == "observe" else None,
+ AddCompileFlag("-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE") if assertion_semantic == "quick_enforce" else None,
+ AddCompileFlag("-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE") if assertion_semantic == "enforce" else None,
+ AddFeature("libcpp-assertion-semantic={}".format(assertion_semantic)) if assertion_semantic != "undefined" else None,
+ ],
+ ),
+ ),
]
# fmt: on
diff --git a/libcxx/utils/synchronize_csv_status_files.py b/libcxx/utils/synchronize_csv_status_files.py
index 3132857..5dbd734 100755
--- a/libcxx/utils/synchronize_csv_status_files.py
+++ b/libcxx/utils/synchronize_csv_status_files.py
@@ -231,7 +231,7 @@ class PaperInfo:
return PaperInfo(
paper_number=paper,
- paper_name=issue['title'],
+ paper_name=issue['title'].removeprefix(paper + ': '),
status=PaperStatus.from_github_issue(issue),
meeting=issue.get('meeting Voted', None),
first_released_version=None, # TODO
@@ -269,14 +269,14 @@ def merge(paper: PaperInfo, gh: PaperInfo) -> PaperInfo:
def load_csv(file: pathlib.Path) -> List[Tuple]:
rows = []
- with open(file, newline='') as f:
+ with open(file, newline='', encoding='utf-8') as f:
reader = csv.reader(f, delimiter=',')
for row in reader:
rows.append(row)
return rows
def write_csv(output: pathlib.Path, rows: List[Tuple]):
- with open(output, 'w', newline='') as f:
+ with open(output, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f, quoting=csv.QUOTE_ALL, lineterminator='\n')
for row in rows:
writer.writerow(row)
@@ -417,7 +417,7 @@ def main(argv):
# Load all the Github issues tracking papers from Github.
if args.load_github_from:
print(f"Loading all issues from {args.load_github_from}")
- with open(args.load_github_from, 'r') as f:
+ with open(args.load_github_from, 'r', encoding='utf-8') as f:
project_info = json.load(f)
else:
print("Loading all issues from Github")
diff --git a/libcxx/vendor/llvm/default_assertion_handler.in b/libcxx/vendor/llvm/default_assertion_handler.in
index f115658..d352405 100644
--- a/libcxx/vendor/llvm/default_assertion_handler.in
+++ b/libcxx/vendor/llvm/default_assertion_handler.in
@@ -16,6 +16,7 @@
# include <__cxx03/__verbose_trap>
#else
# include <__config>
+# include <__log_hardening_failure>
# include <__verbose_abort>
# include <__verbose_trap>
#endif
@@ -24,14 +25,40 @@
# pragma GCC system_header
#endif
-#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
-# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_ABORT("%s", message)
+// Keep the old implementation that doesn't support assertion semantics for backward compatibility with the frozen C++03
+// mode.
+# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_ABORT("%s", message)
+# else
+# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_TRAP(message)
+# endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
#else
-# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_TRAP(message)
+# if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_IGNORE
+# define _LIBCPP_ASSERTION_HANDLER(message) ((void)0)
+
+# elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_OBSERVE
+# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_LOG_HARDENING_FAILURE(message)
+
+# elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
+# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_TRAP(message)
+
+# elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
+# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_ABORT("%s", message)
+
+# else
+
+# error _LIBCPP_ASSERTION_SEMANTIC must be set to one of the following values: \
+_LIBCPP_ASSERTION_SEMANTIC_IGNORE, \
+_LIBCPP_ASSERTION_SEMANTIC_OBSERVE, \
+_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE, \
+_LIBCPP_ASSERTION_SEMANTIC_ENFORCE
+
+# endif // _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_IGNORE
-#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
#endif // _LIBCPP___ASSERTION_HANDLER